History

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

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.

Ingo Molnar committed 14 years ago

Commit 1d787d32 parents ac2ba2b aec193022 files · +683 −90Browse files

Unified · Split

22 files
  1. tools/perf/Documentation/perf-trace.txt +53 −0
  2. tools/perf/Makefile +13 −0
  3. tools/perf/builtin-record.c +1 −1
  4. tools/perf/builtin-stat.c +1 −1
  5. tools/perf/builtin-test.c +118 −2
  6. tools/perf/builtin-top.c +1 −1
  7. tools/perf/builtin-trace.c +310 −0
  8. tools/perf/builtin.h +1 −0
  9. tools/perf/command-list.txt +1 −0
  10. tools/perf/config/feature-tests.mak +11 −0
  11. tools/perf/perf.c +3 −0
  12. tools/perf/util/cpumap.h +11 −0
  13. tools/perf/util/dwarf-aux.c +2 −0
  14. tools/perf/util/evlist.c +34 −27
  15. tools/perf/util/evlist.h +4 −2
  16. tools/perf/util/evsel.c +72 −16
  17. tools/perf/util/evsel.h +16 −2
  18. tools/perf/util/header.c +5 −1
  19. tools/perf/util/hist.c +7 −2
  20. tools/perf/util/parse-events.c +16 −30
  21. tools/perf/util/python.c +1 −1
  22. tools/perf/util/session.c +2 −4
tools/perf/Documentation/perf-trace.txt+53−0
@@ -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]
tools/perf/Makefile+13−0
@@ -559,6 +559,19 @@ else · 558 unmodified lines
559559 LIB_OBJS += $(OUTPUT)util/unwind.o
560560 endif
561561
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+
562575 ifdef NO_NEWT
563576 BASIC_CFLAGS += -DNO_NEWT_SUPPORT
564577 else
tools/perf/builtin-record.c+1−1
@@ -320,7 +320,7 @@ try_again: · 319 unmodified lines
320320 }
321321 }
322322
323− if (perf_evlist__set_filters(evlist)) {
323+ if (perf_evlist__apply_filters(evlist)) {
324324 error("failed to set filter with %d (%s)\n", errno,
325325 strerror(errno));
326326 rc = -1;
tools/perf/builtin-stat.c+1−1
@@ -478,7 +478,7 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv) · 477 unmodified lines
478478 counter->supported = true;
479479 }
480480
481− if (perf_evlist__set_filters(evsel_list)) {
481+ if (perf_evlist__apply_filters(evsel_list)) {
482482 error("failed to set filter with %d (%s)\n", errno,
483483 strerror(errno));
484484 return -1;
tools/perf/builtin-test.c+118−2
@@ -564,7 +564,7 @@ static int test__basic_mmap(void) · 563 unmodified lines
564564 goto out_munmap;
565565 }
566566
567− err = perf_evlist__parse_sample(evlist, event, &sample, false);
567+ err = perf_evlist__parse_sample(evlist, event, &sample);
568568 if (err) {
569569 pr_err("Can't parse sample, err = %d\n", err);
570570 goto out_munmap;
@@ -781,7 +781,7 @@ static int test__PERF_RECORD(void) · 210 unmodified lines
781781 if (type < PERF_RECORD_MAX)
782782 nr_events[type]++;
783783
784− err = perf_evlist__parse_sample(evlist, event, &sample, false);
784+ err = perf_evlist__parse_sample(evlist, event, &sample);
785785 if (err < 0) {
786786 if (verbose)
787787 perf_event__fprintf(event, stderr);
@@ -1289,6 +1289,118 @@ static int perf_evsel__tp_sched_test(void) · 501 unmodified lines
12891289 return ret;
12901290 }
12911291
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+
12921404 static struct test {
12931405 const char *desc;
12941406 int (*func)(void);
@@ -1339,6 +1451,10 @@ static struct test { · 44 unmodified lines
13391451 .desc = "Check parsing of sched tracepoints fields",
13401452 .func = perf_evsel__tp_sched_test,
13411453 },
1454+ {
1455+ .desc = "Generate and check syscalls:sys_enter_open event fields",
1456+ .func = test__syscall_open_tp_fields,
1457+ },
13421458 {
13431459 .func = NULL,
13441460 },
tools/perf/builtin-top.c+1−1
@@ -823,7 +823,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) · 822 unmodified lines
823823 int ret;
824824
825825 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);
827827 if (ret) {
828828 pr_err("Can't parse sample, err = %d\n", ret);
829829 continue;
tools/perf/builtin-trace.c+310−0
@@ -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+}
tools/perf/builtin.h+1−0
@@ -34,6 +34,7 @@ extern int cmd_kmem(int argc, const char **argv, const char *prefix); · 33 unmodified lines
3434 extern int cmd_lock(int argc, const char **argv, const char *prefix);
3535 extern int cmd_kvm(int argc, const char **argv, const char *prefix);
3636 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);
3738 extern int cmd_inject(int argc, const char **argv, const char *prefix);
3839
3940 extern int find_scripts(char **scripts_array, char **scripts_path_array);
tools/perf/command-list.txt+1−0
@@ -17,6 +17,7 @@ perf-report mainporcelain common · 16 unmodified lines
1717 perf-stat mainporcelain common
1818 perf-timechart mainporcelain common
1919 perf-top mainporcelain common
20+perf-trace mainporcelain common
2021 perf-script mainporcelain common
2122 perf-probe mainporcelain full
2223 perf-kmem mainporcelain common
tools/perf/config/feature-tests.mak+11−0
@@ -193,3 +193,14 @@ int main(void) · 192 unmodified lines
193193 }
194194 endef
195195 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
tools/perf/perf.c+3−0
@@ -55,6 +55,9 @@ static struct cmd_struct commands[] = { · 54 unmodified lines
5555 { "lock", cmd_lock, 0 },
5656 { "kvm", cmd_kvm, 0 },
5757 { "test", cmd_test, 0 },
58+#ifndef NO_LIBAUDIT_SUPPORT
59+ { "trace", cmd_trace, 0 },
60+#endif
5861 { "inject", cmd_inject, 0 },
5962 };
6063
tools/perf/util/cpumap.h+11−0
@@ -2,6 +2,7 @@ · 1 unmodified line
22 #define __PERF_CPUMAP_H
33
44 #include <stdio.h>
5+#include <stdbool.h>
56
67 struct cpu_map {
78 int nr;
@@ -14,4 +15,14 @@ void cpu_map__delete(struct cpu_map *map); · 6 unmodified lines
1415 struct cpu_map *cpu_map__read(FILE *file);
1516 size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
1617
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+
1728 #endif /* __PERF_CPUMAP_H */
tools/perf/util/dwarf-aux.c+2−0
@@ -804,6 +804,8 @@ int die_get_typename(Dwarf_Die *vr_die, char *buf, int len) · 803 unmodified lines
804804 tmp = "union ";
805805 else if (tag == DW_TAG_structure_type)
806806 tmp = "struct ";
807+ else if (tag == DW_TAG_enumeration_type)
808+ tmp = "enum ";
807809 /* Write a base name */
808810 ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
809811 return (ret >= len) ? -E2BIG : ret;
tools/perf/util/evlist.c+34−27
@@ -304,7 +304,7 @@ void perf_evlist__enable(struct perf_evlist *evlist) · 303 unmodified lines
304304 int cpu, thread;
305305 struct perf_evsel *pos;
306306
307− for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
307+ for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) {
308308 list_for_each_entry(pos, &evlist->entries, node) {
309309 for (thread = 0; thread < evlist->threads->nr; thread++)
310310 ioctl(FD(pos, cpu, thread),
@@ -315,7 +315,7 @@ void perf_evlist__enable(struct perf_evlist *evlist) · 4 unmodified lines
315315
316316 static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
317317 {
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;
319319 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
320320 return evlist->pollfd != NULL ? 0 : -ENOMEM;
321321 }
@@ -475,8 +475,8 @@ void perf_evlist__munmap(struct perf_evlist *evlist) · 153 unmodified lines
475475
476476 static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
477477 {
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))
480480 evlist->nr_mmaps = evlist->threads->nr;
481481 evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
482482 return evlist->mmap != NULL ? 0 : -ENOMEM;
@@ -622,11 +622,11 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, · 139 unmodified lines
622622 list_for_each_entry(evsel, &evlist->entries, node) {
623623 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
624624 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)
626626 return -ENOMEM;
627627 }
628628
629− if (evlist->cpus->map[0] == -1)
629+ if (cpu_map__all(cpus))
630630 return perf_evlist__mmap_per_thread(evlist, prot, mask);
631631
632632 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
666666 evlist->threads = NULL;
667667 }
668668
669−int perf_evlist__set_filters(struct perf_evlist *evlist)
669+int perf_evlist__apply_filters(struct perf_evlist *evlist)
670670 {
671− const struct thread_map *threads = evlist->threads;
672− const struct cpu_map *cpus = evlist->cpus;
673671 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;
679675
680676 list_for_each_entry(evsel, &evlist->entries, node) {
681− filter = evsel->filter;
682− if (!filter)
677+ if (evsel->filter == NULL)
683678 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;
692683 }
693684
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;
695702 }
696703
697704 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
884891 }
885892
886893 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)
888895 {
889896 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);
891898 }
892899
893900 size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp)
tools/perf/util/evlist.h+4−2
@@ -72,6 +72,8 @@ int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, · 71 unmodified lines
7272 #define perf_evlist__set_tracepoints_handlers_array(evlist, array) \
7373 perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array))
7474
75+int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter);
76+
7577 struct perf_evsel *
7678 perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id);
7779
@@ -115,7 +117,7 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist, · 37 unmodified lines
115117 int perf_evlist__create_maps(struct perf_evlist *evlist,
116118 struct perf_target *target);
117119 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);
119121
120122 void __perf_evlist__set_leader(struct list_head *list);
121123 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
125127 u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist);
126128
127129 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);
129131
130132 bool perf_evlist__valid_sample_type(struct perf_evlist *evlist);
131133 bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist);
tools/perf/util/evsel.c+72−16
@@ -70,7 +70,7 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) · 69 unmodified lines
7070 return evsel;
7171 }
7272
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)
7474 {
7575 int fd, n;
7676 char *filename;
@@ -117,21 +117,28 @@ struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx) · 40 unmodified lines
117117
118118 if (evsel != NULL) {
119119 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),
121123 };
122124
125+ if (asprintf(&evsel->name, "%s:%s", sys, name) < 0)
126+ goto out_free;
127+
123128 evsel->tp_format = event_format__new(sys, name);
124129 if (evsel->tp_format == NULL)
125130 goto out_free;
126131
132+ event_attr_init(&attr);
127133 attr.config = evsel->tp_format->id;
134+ attr.sample_period = 1;
128135 perf_evsel__init(evsel, &attr, idx);
129− evsel->name = evsel->tp_format->name;
130136 }
131137
132138 return evsel;
133139
134140 out_free:
141+ free(evsel->name);
135142 free(evsel);
136143 return NULL;
137144 }
@@ -501,6 +508,24 @@ int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) · 363 unmodified lines
501508 return evsel->fd != NULL ? 0 : -ENOMEM;
502509 }
503510
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+
504529 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
505530 {
506531 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
562587 perf_evsel__exit(evsel);
563588 close_cgroup(evsel->cgrp);
564589 free(evsel->group_name);
565− if (evsel->tp_format && evsel->name == evsel->tp_format->name) {
566− evsel->name = NULL;
590+ if (evsel->tp_format)
567591 pevent_free_format(evsel->tp_format);
568− }
569592 free(evsel->name);
570593 free(evsel);
571594 }
@@ -763,11 +786,13 @@ int perf_evsel__open_per_thread(struct perf_evsel *evsel, · 191 unmodified lines
763786 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads);
764787 }
765788
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)
769792 {
793+ u64 type = evsel->attr.sample_type;
770794 const u64 *array = event->sample.array;
795+ bool swapped = evsel->needs_swap;
771796 union u64_swap u;
772797
773798 array += ((event->header.size -
@@ -828,10 +853,11 @@ static bool sample_overlap(const union perf_event *event, · 54 unmodified lines
828853 }
829854
830855 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)
832857 {
833858 u64 type = evsel->attr.sample_type;
834859 u64 regs_user = evsel->attr.sample_regs_user;
860+ bool swapped = evsel->needs_swap;
835861 const u64 *array;
836862
837863 /*
@@ -848,7 +874,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, · 10 unmodified lines
848874 if (event->header.type != PERF_RECORD_SAMPLE) {
849875 if (!evsel->attr.sample_id_all)
850876 return 0;
851− return perf_event__parse_id_sample(event, type, data, swapped);
877+ return perf_evsel__parse_id_sample(evsel, event, data);
852878 }
853879
854880 array = event->sample.array;
@@ -1078,7 +1104,7 @@ struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *nam · 223 unmodified lines
10781104 return pevent_find_field(evsel->tp_format, name);
10791105 }
10801106
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,
10821108 const char *name)
10831109 {
10841110 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
11011127 const char *name)
11021128 {
11031129 struct format_field *field = perf_evsel__field(evsel, name);
1104− u64 val;
1130+ void *ptr;
1131+ u64 value;
11051132
11061133 if (!field)
11071134 return 0;
11081135
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;
11121137
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;
11131169 }
tools/perf/util/evsel.h+16−2
@@ -69,6 +69,7 @@ struct perf_evsel { · 68 unmodified lines
6969 struct cpu_map *cpus;
7070 unsigned int sample_size;
7171 bool supported;
72+ bool needs_swap;
7273 /* parse modifier helper */
7374 int exclude_GH;
7475 struct perf_evsel *leader;
@@ -82,6 +83,9 @@ struct perf_record_opts; · 7 unmodified lines
8283
8384 struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx);
8485 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+
8589 void perf_evsel__init(struct perf_evsel *evsel,
8690 struct perf_event_attr *attr, int idx);
8791 void perf_evsel__exit(struct perf_evsel *evsel);
@@ -114,6 +118,9 @@ void perf_evsel__free_fd(struct perf_evsel *evsel); · 26 unmodified lines
114118 void perf_evsel__free_id(struct perf_evsel *evsel);
115119 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
116120
121+int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
122+ const char *filter);
123+
117124 int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
118125 struct cpu_map *cpus);
119126 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
124131
125132 struct perf_sample;
126133
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,
128135 const char *name);
129136 u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample,
130137 const char *name);
131138
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+
132146 struct format_field;
133147
134148 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
205219 void hists__init(struct hists *hists);
206220
207221 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);
209223
210224 static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel)
211225 {
tools/perf/util/header.c+5−1
@@ -1256,8 +1256,10 @@ read_event_desc(struct perf_header *ph, int fd) · 1255 unmodified lines
12561256 if (ret != (ssize_t)sizeof(nr))
12571257 goto error;
12581258
1259− if (ph->needs_swap)
1259+ if (ph->needs_swap) {
12601260 nr = bswap_32(nr);
1261+ evsel->needs_swap = true;
1262+ }
12611263
12621264 evsel->name = do_read_string(fd, ph);
12631265
@@ -2626,6 +2628,8 @@ int perf_session__read_header(struct perf_session *session, int fd) · 1362 unmodified lines
26262628
26272629 if (evsel == NULL)
26282630 goto out_delete_evlist;
2631+
2632+ evsel->needs_swap = header->needs_swap;
26292633 /*
26302634 * Do it before so that if perf_evsel__alloc_id fails, this
26312635 * entry gets purged too at perf_evlist__delete().
tools/perf/util/hist.c+7−2
@@ -410,8 +410,13 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, · 409 unmodified lines
410410 cmp = hist_entry__collapse(iter, he);
411411
412412 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+
415420 if (symbol_conf.use_callchain) {
416421 callchain_cursor_reset(&callchain_cursor);
417422 callchain_merge(&callchain_cursor,
tools/perf/util/parse-events.c+16−30
@@ -356,42 +356,28 @@ int parse_events_add_cache(struct list_head **list, int *idx, · 355 unmodified lines
356356 return add_event(list, idx, &attr, name);
357357 }
358358
359−static int add_tracepoint(struct list_head **list, int *idx,
359+static int add_tracepoint(struct list_head **listp, int *idx,
360360 char *sys_name, char *evt_name)
361361 {
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;
375364
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);
379370 }
380371
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+ }
392377
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;
395381 }
396382
397383 static int add_tracepoint_multi(struct list_head **list, int *idx,
tools/perf/util/python.c+1−1
@@ -805,7 +805,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, · 804 unmodified lines
805805 if (pyevent == NULL)
806806 return PyErr_NoMemory();
807807
808− err = perf_evlist__parse_sample(evlist, event, &pevent->sample, false);
808+ err = perf_evlist__parse_sample(evlist, event, &pevent->sample);
809809 if (err)
810810 return PyErr_Format(PyExc_OSError,
811811 "perf: can't parse sample, err=%d", err);
tools/perf/util/session.c+2−4
@@ -722,8 +722,7 @@ static int flush_sample_queue(struct perf_session *s, · 721 unmodified lines
722722 if (iter->timestamp > limit)
723723 break;
724724
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);
727726 if (ret)
728727 pr_err("Can't parse sample, err = %d\n", ret);
729728 else {
@@ -1174,8 +1173,7 @@ static int perf_session__process_event(struct perf_session *session, · 444 unmodified lines
11741173 /*
11751174 * For all kernel events we get the sample data
11761175 */
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);
11791177 if (ret)
11801178 return ret;
11811179