aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2013-09-03 01:46:19 -0400
committerIngo Molnar <mingo@kernel.org>2013-09-03 01:46:19 -0400
commit61bf86ad86443a710ae7eed372cccb8ed5038eda (patch)
treedf2ef6df950e698f14dde31f740101e7d80a9781
parent7bfb7e6bdd906f11ee9e751b3fec4f4fc728e818 (diff)
parent31cd3855c98119cae287b761d8d2e75018714c5d (diff)
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: * 'perf trace' arg formatting improvements to allow masking arguments in syscalls such as futex and open, where the some arguments are ignored and thus should not be printed depending on other args. * Beautify futex open, openat, open_by_handle_at, lseek and futex syscalls. * Add dummy software event to use when wanting just to keep receiving PERF_RECORD_{MMAP,COMM,etc}, add test for it, from Adrian Hunter. * Fix symbol offset computation for some dsos in 'perf script', from David Ahern. * Skip unsupported hardware events in 'perf list', from Namhyung Kim. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--include/uapi/linux/perf_event.h1
-rw-r--r--tools/perf/Makefile1
-rw-r--r--tools/perf/builtin-trace.c180
-rw-r--r--tools/perf/tests/builtin-test.c4
-rw-r--r--tools/perf/tests/keep-tracking.c154
-rw-r--r--tools/perf/tests/tests.h1
-rw-r--r--tools/perf/util/evlist.c42
-rw-r--r--tools/perf/util/evlist.h5
-rw-r--r--tools/perf/util/evsel.c1
-rw-r--r--tools/perf/util/parse-events.c45
-rw-r--r--tools/perf/util/parse-events.l1
-rw-r--r--tools/perf/util/python.c1
-rw-r--r--tools/perf/util/session.c1
-rw-r--r--tools/perf/util/symbol.c5
14 files changed, 424 insertions, 18 deletions
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 408b8c730731..ca1d90bcb74d 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -109,6 +109,7 @@ enum perf_sw_ids {
109 PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6, 109 PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
110 PERF_COUNT_SW_ALIGNMENT_FAULTS = 7, 110 PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
111 PERF_COUNT_SW_EMULATION_FAULTS = 8, 111 PERF_COUNT_SW_EMULATION_FAULTS = 8,
112 PERF_COUNT_SW_DUMMY = 9,
112 113
113 PERF_COUNT_SW_MAX, /* non-ABI */ 114 PERF_COUNT_SW_MAX, /* non-ABI */
114}; 115};
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index ecebfd00295e..c5dc1ad1b8d7 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -465,6 +465,7 @@ endif # NO_LIBELF
465ifndef NO_LIBUNWIND 465ifndef NO_LIBUNWIND
466 LIB_OBJS += $(OUTPUT)util/unwind.o 466 LIB_OBJS += $(OUTPUT)util/unwind.o
467endif 467endif
468LIB_OBJS += $(OUTPUT)tests/keep-tracking.o
468 469
469ifndef NO_LIBAUDIT 470ifndef NO_LIBAUDIT
470 BUILTIN_OBJS += $(OUTPUT)builtin-trace.o 471 BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 69a065e51135..b6f0725068bd 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -14,15 +14,49 @@
14#include <libaudit.h> 14#include <libaudit.h>
15#include <stdlib.h> 15#include <stdlib.h>
16#include <sys/mman.h> 16#include <sys/mman.h>
17#include <linux/futex.h>
17 18
18static size_t syscall_arg__scnprintf_hex(char *bf, size_t size, unsigned long arg) 19static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
20 unsigned long arg,
21 u8 arg_idx __maybe_unused,
22 u8 *arg_mask __maybe_unused)
19{ 23{
20 return scnprintf(bf, size, "%#lx", arg); 24 return scnprintf(bf, size, "%#lx", arg);
21} 25}
22 26
23#define SCA_HEX syscall_arg__scnprintf_hex 27#define SCA_HEX syscall_arg__scnprintf_hex
24 28
25static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, unsigned long arg) 29static size_t syscall_arg__scnprintf_whence(char *bf, size_t size,
30 unsigned long arg,
31 u8 arg_idx __maybe_unused,
32 u8 *arg_mask __maybe_unused)
33{
34 int whence = arg;
35
36 switch (whence) {
37#define P_WHENCE(n) case SEEK_##n: return scnprintf(bf, size, #n)
38 P_WHENCE(SET);
39 P_WHENCE(CUR);
40 P_WHENCE(END);
41#ifdef SEEK_DATA
42 P_WHENCE(DATA);
43#endif
44#ifdef SEEK_HOLE
45 P_WHENCE(HOLE);
46#endif
47#undef P_WHENCE
48 default: break;
49 }
50
51 return scnprintf(bf, size, "%#x", whence);
52}
53
54#define SCA_WHENCE syscall_arg__scnprintf_whence
55
56static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
57 unsigned long arg,
58 u8 arg_idx __maybe_unused,
59 u8 *arg_mask __maybe_unused)
26{ 60{
27 int printed = 0, prot = arg; 61 int printed = 0, prot = arg;
28 62
@@ -52,7 +86,9 @@ static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, unsigned l
52 86
53#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot 87#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
54 88
55static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, unsigned long arg) 89static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
90 unsigned long arg, u8 arg_idx __maybe_unused,
91 u8 *arg_mask __maybe_unused)
56{ 92{
57 int printed = 0, flags = arg; 93 int printed = 0, flags = arg;
58 94
@@ -92,7 +128,9 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, unsigned
92 128
93#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags 129#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
94 130
95static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, unsigned long arg) 131static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
132 unsigned long arg, u8 arg_idx __maybe_unused,
133 u8 *arg_mask __maybe_unused)
96{ 134{
97 int behavior = arg; 135 int behavior = arg;
98 136
@@ -133,10 +171,111 @@ static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, uns
133 171
134#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior 172#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
135 173
174static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, unsigned long arg,
175 u8 arg_idx __maybe_unused, u8 *arg_mask)
176{
177 enum syscall_futex_args {
178 SCF_UADDR = (1 << 0),
179 SCF_OP = (1 << 1),
180 SCF_VAL = (1 << 2),
181 SCF_TIMEOUT = (1 << 3),
182 SCF_UADDR2 = (1 << 4),
183 SCF_VAL3 = (1 << 5),
184 };
185 int op = arg;
186 int cmd = op & FUTEX_CMD_MASK;
187 size_t printed = 0;
188
189 switch (cmd) {
190#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
191 P_FUTEX_OP(WAIT); *arg_mask |= SCF_VAL3|SCF_UADDR2; break;
192 P_FUTEX_OP(WAKE); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
193 P_FUTEX_OP(FD); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
194 P_FUTEX_OP(REQUEUE); *arg_mask |= SCF_VAL3|SCF_TIMEOUT; break;
195 P_FUTEX_OP(CMP_REQUEUE); *arg_mask |= SCF_TIMEOUT; break;
196 P_FUTEX_OP(CMP_REQUEUE_PI); *arg_mask |= SCF_TIMEOUT; break;
197 P_FUTEX_OP(WAKE_OP); break;
198 P_FUTEX_OP(LOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
199 P_FUTEX_OP(UNLOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
200 P_FUTEX_OP(TRYLOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2; break;
201 P_FUTEX_OP(WAIT_BITSET); *arg_mask |= SCF_UADDR2; break;
202 P_FUTEX_OP(WAKE_BITSET); *arg_mask |= SCF_UADDR2; break;
203 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
204 default: printed = scnprintf(bf, size, "%#x", cmd); break;
205 }
206
207 if (op & FUTEX_PRIVATE_FLAG)
208 printed += scnprintf(bf + printed, size - printed, "|PRIV");
209
210 if (op & FUTEX_CLOCK_REALTIME)
211 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
212
213 return printed;
214}
215
216#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
217
218static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
219 unsigned long arg,
220 u8 arg_idx, u8 *arg_mask)
221{
222 int printed = 0, flags = arg;
223
224 if (!(flags & O_CREAT))
225 *arg_mask |= 1 << (arg_idx + 1); /* Mask the mode parm */
226
227 if (flags == 0)
228 return scnprintf(bf, size, "RDONLY");
229#define P_FLAG(n) \
230 if (flags & O_##n) { \
231 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
232 flags &= ~O_##n; \
233 }
234
235 P_FLAG(APPEND);
236 P_FLAG(ASYNC);
237 P_FLAG(CLOEXEC);
238 P_FLAG(CREAT);
239 P_FLAG(DIRECT);
240 P_FLAG(DIRECTORY);
241 P_FLAG(EXCL);
242 P_FLAG(LARGEFILE);
243 P_FLAG(NOATIME);
244 P_FLAG(NOCTTY);
245#ifdef O_NONBLOCK
246 P_FLAG(NONBLOCK);
247#elif O_NDELAY
248 P_FLAG(NDELAY);
249#endif
250#ifdef O_PATH
251 P_FLAG(PATH);
252#endif
253 P_FLAG(RDWR);
254#ifdef O_DSYNC
255 if ((flags & O_SYNC) == O_SYNC)
256 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
257 else {
258 P_FLAG(DSYNC);
259 }
260#else
261 P_FLAG(SYNC);
262#endif
263 P_FLAG(TRUNC);
264 P_FLAG(WRONLY);
265#undef P_FLAG
266
267 if (flags)
268 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
269
270 return printed;
271}
272
273#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
274
136static struct syscall_fmt { 275static struct syscall_fmt {
137 const char *name; 276 const char *name;
138 const char *alias; 277 const char *alias;
139 size_t (*arg_scnprintf[6])(char *bf, size_t size, unsigned long arg); 278 size_t (*arg_scnprintf[6])(char *bf, size_t size, unsigned long arg, u8 arg_idx, u8 *arg_mask);
140 bool errmsg; 279 bool errmsg;
141 bool timeout; 280 bool timeout;
142 bool hexret; 281 bool hexret;
@@ -149,9 +288,12 @@ static struct syscall_fmt {
149 { .name = "connect", .errmsg = true, }, 288 { .name = "connect", .errmsg = true, },
150 { .name = "fstat", .errmsg = true, .alias = "newfstat", }, 289 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
151 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", }, 290 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
152 { .name = "futex", .errmsg = true, }, 291 { .name = "futex", .errmsg = true,
292 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
153 { .name = "ioctl", .errmsg = true, 293 { .name = "ioctl", .errmsg = true,
154 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, }, 294 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
295 { .name = "lseek", .errmsg = true,
296 .arg_scnprintf = { [2] = SCA_WHENCE, /* whence */ }, },
155 { .name = "lstat", .errmsg = true, .alias = "newlstat", }, 297 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
156 { .name = "madvise", .errmsg = true, 298 { .name = "madvise", .errmsg = true,
157 .arg_scnprintf = { [0] = SCA_HEX, /* start */ 299 .arg_scnprintf = { [0] = SCA_HEX, /* start */
@@ -168,7 +310,12 @@ static struct syscall_fmt {
168 [4] = SCA_HEX, /* new_addr */ }, }, 310 [4] = SCA_HEX, /* new_addr */ }, },
169 { .name = "munmap", .errmsg = true, 311 { .name = "munmap", .errmsg = true,
170 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, 312 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
171 { .name = "open", .errmsg = true, }, 313 { .name = "open", .errmsg = true,
314 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
315 { .name = "open_by_handle_at", .errmsg = true,
316 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
317 { .name = "openat", .errmsg = true,
318 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
172 { .name = "poll", .errmsg = true, .timeout = true, }, 319 { .name = "poll", .errmsg = true, .timeout = true, },
173 { .name = "ppoll", .errmsg = true, .timeout = true, }, 320 { .name = "ppoll", .errmsg = true, .timeout = true, },
174 { .name = "pread", .errmsg = true, .alias = "pread64", }, 321 { .name = "pread", .errmsg = true, .alias = "pread64", },
@@ -198,7 +345,8 @@ struct syscall {
198 const char *name; 345 const char *name;
199 bool filtered; 346 bool filtered;
200 struct syscall_fmt *fmt; 347 struct syscall_fmt *fmt;
201 size_t (**arg_scnprintf)(char *bf, size_t size, unsigned long arg); 348 size_t (**arg_scnprintf)(char *bf, size_t size,
349 unsigned long arg, u8 arg_idx, u8 *args_mask);
202}; 350};
203 351
204static size_t fprintf_duration(unsigned long t, FILE *fp) 352static size_t fprintf_duration(unsigned long t, FILE *fp)
@@ -443,17 +591,23 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
443 591
444 if (sc->tp_format != NULL) { 592 if (sc->tp_format != NULL) {
445 struct format_field *field; 593 struct format_field *field;
594 u8 mask = 0, bit = 1;
595
596 for (field = sc->tp_format->format.fields->next; field;
597 field = field->next, ++i, bit <<= 1) {
598 if (mask & bit)
599 continue;
446 600
447 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
448 printed += scnprintf(bf + printed, size - printed, 601 printed += scnprintf(bf + printed, size - printed,
449 "%s%s: ", printed ? ", " : "", field->name); 602 "%s%s: ", printed ? ", " : "", field->name);
450 603
451 if (sc->arg_scnprintf && sc->arg_scnprintf[i]) 604 if (sc->arg_scnprintf && sc->arg_scnprintf[i]) {
452 printed += sc->arg_scnprintf[i](bf + printed, size - printed, args[i]); 605 printed += sc->arg_scnprintf[i](bf + printed, size - printed,
453 else 606 args[i], i, &mask);
607 } else {
454 printed += scnprintf(bf + printed, size - printed, 608 printed += scnprintf(bf + printed, size - printed,
455 "%ld", args[i]); 609 "%ld", args[i]);
456 ++i; 610 }
457 } 611 }
458 } else { 612 } else {
459 while (i < 6) { 613 while (i < 6) {
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 8ad9415dd847..8bbeba322df9 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -108,6 +108,10 @@ static struct test {
108 .func = test__sample_parsing, 108 .func = test__sample_parsing,
109 }, 109 },
110 { 110 {
111 .desc = "Test using a dummy software event to keep tracking",
112 .func = test__keep_tracking,
113 },
114 {
111 .func = NULL, 115 .func = NULL,
112 }, 116 },
113}; 117};
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
new file mode 100644
index 000000000000..d444ea2c47d9
--- /dev/null
+++ b/tools/perf/tests/keep-tracking.c
@@ -0,0 +1,154 @@
1#include <sys/types.h>
2#include <unistd.h>
3#include <sys/prctl.h>
4
5#include "parse-events.h"
6#include "evlist.h"
7#include "evsel.h"
8#include "thread_map.h"
9#include "cpumap.h"
10#include "tests.h"
11
12#define CHECK__(x) { \
13 while ((x) < 0) { \
14 pr_debug(#x " failed!\n"); \
15 goto out_err; \
16 } \
17}
18
19#define CHECK_NOT_NULL__(x) { \
20 while ((x) == NULL) { \
21 pr_debug(#x " failed!\n"); \
22 goto out_err; \
23 } \
24}
25
26static int find_comm(struct perf_evlist *evlist, const char *comm)
27{
28 union perf_event *event;
29 int i, found;
30
31 found = 0;
32 for (i = 0; i < evlist->nr_mmaps; i++) {
33 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
34 if (event->header.type == PERF_RECORD_COMM &&
35 (pid_t)event->comm.pid == getpid() &&
36 (pid_t)event->comm.tid == getpid() &&
37 strcmp(event->comm.comm, comm) == 0)
38 found += 1;
39 }
40 }
41 return found;
42}
43
44/**
45 * test__keep_tracking - test using a dummy software event to keep tracking.
46 *
47 * This function implements a test that checks that tracking events continue
48 * when an event is disabled but a dummy software event is not disabled. If the
49 * test passes %0 is returned, otherwise %-1 is returned.
50 */
51int test__keep_tracking(void)
52{
53 struct perf_record_opts opts = {
54 .mmap_pages = UINT_MAX,
55 .user_freq = UINT_MAX,
56 .user_interval = ULLONG_MAX,
57 .freq = 4000,
58 .target = {
59 .uses_mmap = true,
60 },
61 };
62 struct thread_map *threads = NULL;
63 struct cpu_map *cpus = NULL;
64 struct perf_evlist *evlist = NULL;
65 struct perf_evsel *evsel = NULL;
66 int found, err = -1;
67 const char *comm;
68
69 threads = thread_map__new(-1, getpid(), UINT_MAX);
70 CHECK_NOT_NULL__(threads);
71
72 cpus = cpu_map__new(NULL);
73 CHECK_NOT_NULL__(cpus);
74
75 evlist = perf_evlist__new();
76 CHECK_NOT_NULL__(evlist);
77
78 perf_evlist__set_maps(evlist, cpus, threads);
79
80 CHECK__(parse_events(evlist, "dummy:u"));
81 CHECK__(parse_events(evlist, "cycles:u"));
82
83 perf_evlist__config(evlist, &opts);
84
85 evsel = perf_evlist__first(evlist);
86
87 evsel->attr.comm = 1;
88 evsel->attr.disabled = 1;
89 evsel->attr.enable_on_exec = 0;
90
91 if (perf_evlist__open(evlist) < 0) {
92 fprintf(stderr, " (not supported)");
93 err = 0;
94 goto out_err;
95 }
96
97 CHECK__(perf_evlist__mmap(evlist, UINT_MAX, false));
98
99 /*
100 * First, test that a 'comm' event can be found when the event is
101 * enabled.
102 */
103
104 perf_evlist__enable(evlist);
105
106 comm = "Test COMM 1";
107 CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0));
108
109 perf_evlist__disable(evlist);
110
111 found = find_comm(evlist, comm);
112 if (found != 1) {
113 pr_debug("First time, failed to find tracking event.\n");
114 goto out_err;
115 }
116
117 /*
118 * Secondly, test that a 'comm' event can be found when the event is
119 * disabled with the dummy event still enabled.
120 */
121
122 perf_evlist__enable(evlist);
123
124 evsel = perf_evlist__last(evlist);
125
126 CHECK__(perf_evlist__disable_event(evlist, evsel));
127
128 comm = "Test COMM 2";
129 CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0));
130
131 perf_evlist__disable(evlist);
132
133 found = find_comm(evlist, comm);
134 if (found != 1) {
135 pr_debug("Seconf time, failed to find tracking event.\n");
136 goto out_err;
137 }
138
139 err = 0;
140
141out_err:
142 if (evlist) {
143 perf_evlist__disable(evlist);
144 perf_evlist__munmap(evlist);
145 perf_evlist__close(evlist);
146 perf_evlist__delete(evlist);
147 }
148 if (cpus)
149 cpu_map__delete(cpus);
150 if (threads)
151 thread_map__delete(threads);
152
153 return err;
154}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 83d5b71a3ce4..c048b589998a 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -38,5 +38,6 @@ int test__sw_clock_freq(void);
38int test__perf_time_to_tsc(void); 38int test__perf_time_to_tsc(void);
39int test__code_reading(void); 39int test__code_reading(void);
40int test__sample_parsing(void); 40int test__sample_parsing(void);
41int test__keep_tracking(void);
41 42
42#endif /* TESTS_H */ 43#endif /* TESTS_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 5df4ca91bed3..b8727ae45e3b 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -246,7 +246,7 @@ void perf_evlist__disable(struct perf_evlist *evlist)
246 246
247 for (cpu = 0; cpu < nr_cpus; cpu++) { 247 for (cpu = 0; cpu < nr_cpus; cpu++) {
248 list_for_each_entry(pos, &evlist->entries, node) { 248 list_for_each_entry(pos, &evlist->entries, node) {
249 if (!perf_evsel__is_group_leader(pos)) 249 if (!perf_evsel__is_group_leader(pos) || !pos->fd)
250 continue; 250 continue;
251 for (thread = 0; thread < nr_threads; thread++) 251 for (thread = 0; thread < nr_threads; thread++)
252 ioctl(FD(pos, cpu, thread), 252 ioctl(FD(pos, cpu, thread),
@@ -264,7 +264,7 @@ void perf_evlist__enable(struct perf_evlist *evlist)
264 264
265 for (cpu = 0; cpu < nr_cpus; cpu++) { 265 for (cpu = 0; cpu < nr_cpus; cpu++) {
266 list_for_each_entry(pos, &evlist->entries, node) { 266 list_for_each_entry(pos, &evlist->entries, node) {
267 if (!perf_evsel__is_group_leader(pos)) 267 if (!perf_evsel__is_group_leader(pos) || !pos->fd)
268 continue; 268 continue;
269 for (thread = 0; thread < nr_threads; thread++) 269 for (thread = 0; thread < nr_threads; thread++)
270 ioctl(FD(pos, cpu, thread), 270 ioctl(FD(pos, cpu, thread),
@@ -273,6 +273,44 @@ void perf_evlist__enable(struct perf_evlist *evlist)
273 } 273 }
274} 274}
275 275
276int perf_evlist__disable_event(struct perf_evlist *evlist,
277 struct perf_evsel *evsel)
278{
279 int cpu, thread, err;
280
281 if (!evsel->fd)
282 return 0;
283
284 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
285 for (thread = 0; thread < evlist->threads->nr; thread++) {
286 err = ioctl(FD(evsel, cpu, thread),
287 PERF_EVENT_IOC_DISABLE, 0);
288 if (err)
289 return err;
290 }
291 }
292 return 0;
293}
294
295int perf_evlist__enable_event(struct perf_evlist *evlist,
296 struct perf_evsel *evsel)
297{
298 int cpu, thread, err;
299
300 if (!evsel->fd)
301 return -EINVAL;
302
303 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
304 for (thread = 0; thread < evlist->threads->nr; thread++) {
305 err = ioctl(FD(evsel, cpu, thread),
306 PERF_EVENT_IOC_ENABLE, 0);
307 if (err)
308 return err;
309 }
310 }
311 return 0;
312}
313
276static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) 314static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
277{ 315{
278 int nr_cpus = cpu_map__nr(evlist->cpus); 316 int nr_cpus = cpu_map__nr(evlist->cpus);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 841a39405f6a..880d7139d2fb 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -110,6 +110,11 @@ void perf_evlist__munmap(struct perf_evlist *evlist);
110void perf_evlist__disable(struct perf_evlist *evlist); 110void perf_evlist__disable(struct perf_evlist *evlist);
111void perf_evlist__enable(struct perf_evlist *evlist); 111void perf_evlist__enable(struct perf_evlist *evlist);
112 112
113int perf_evlist__disable_event(struct perf_evlist *evlist,
114 struct perf_evsel *evsel);
115int perf_evlist__enable_event(struct perf_evlist *evlist,
116 struct perf_evsel *evsel);
117
113void perf_evlist__set_selected(struct perf_evlist *evlist, 118void perf_evlist__set_selected(struct perf_evlist *evlist,
114 struct perf_evsel *evsel); 119 struct perf_evsel *evsel);
115 120
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index e8745fb635a7..3612183e2cc5 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -323,6 +323,7 @@ const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = {
323 "major-faults", 323 "major-faults",
324 "alignment-faults", 324 "alignment-faults",
325 "emulation-faults", 325 "emulation-faults",
326 "dummy",
326}; 327};
327 328
328static const char *__perf_evsel__sw_name(u64 config) 329static const char *__perf_evsel__sw_name(u64 config)
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 9cba92386a82..98125319b158 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -15,6 +15,7 @@
15#define YY_EXTRA_TYPE int 15#define YY_EXTRA_TYPE int
16#include "parse-events-flex.h" 16#include "parse-events-flex.h"
17#include "pmu.h" 17#include "pmu.h"
18#include "thread_map.h"
18 19
19#define MAX_NAME_LEN 100 20#define MAX_NAME_LEN 100
20 21
@@ -108,6 +109,10 @@ static struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = {
108 .symbol = "emulation-faults", 109 .symbol = "emulation-faults",
109 .alias = "", 110 .alias = "",
110 }, 111 },
112 [PERF_COUNT_SW_DUMMY] = {
113 .symbol = "dummy",
114 .alias = "",
115 },
111}; 116};
112 117
113#define __PERF_EVENT_FIELD(config, name) \ 118#define __PERF_EVENT_FIELD(config, name) \
@@ -1072,6 +1077,33 @@ int is_valid_tracepoint(const char *event_string)
1072 return 0; 1077 return 0;
1073} 1078}
1074 1079
1080static bool is_event_supported(u8 type, unsigned config)
1081{
1082 bool ret = true;
1083 struct perf_evsel *evsel;
1084 struct perf_event_attr attr = {
1085 .type = type,
1086 .config = config,
1087 .disabled = 1,
1088 .exclude_kernel = 1,
1089 };
1090 struct {
1091 struct thread_map map;
1092 int threads[1];
1093 } tmap = {
1094 .map.nr = 1,
1095 .threads = { 0 },
1096 };
1097
1098 evsel = perf_evsel__new(&attr, 0);
1099 if (evsel) {
1100 ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0;
1101 perf_evsel__delete(evsel);
1102 }
1103
1104 return ret;
1105}
1106
1075static void __print_events_type(u8 type, struct event_symbol *syms, 1107static void __print_events_type(u8 type, struct event_symbol *syms,
1076 unsigned max) 1108 unsigned max)
1077{ 1109{
@@ -1079,14 +1111,16 @@ static void __print_events_type(u8 type, struct event_symbol *syms,
1079 unsigned i; 1111 unsigned i;
1080 1112
1081 for (i = 0; i < max ; i++, syms++) { 1113 for (i = 0; i < max ; i++, syms++) {
1114 if (!is_event_supported(type, i))
1115 continue;
1116
1082 if (strlen(syms->alias)) 1117 if (strlen(syms->alias))
1083 snprintf(name, sizeof(name), "%s OR %s", 1118 snprintf(name, sizeof(name), "%s OR %s",
1084 syms->symbol, syms->alias); 1119 syms->symbol, syms->alias);
1085 else 1120 else
1086 snprintf(name, sizeof(name), "%s", syms->symbol); 1121 snprintf(name, sizeof(name), "%s", syms->symbol);
1087 1122
1088 printf(" %-50s [%s]\n", name, 1123 printf(" %-50s [%s]\n", name, event_type_descriptors[type]);
1089 event_type_descriptors[type]);
1090 } 1124 }
1091} 1125}
1092 1126
@@ -1115,6 +1149,10 @@ int print_hwcache_events(const char *event_glob, bool name_only)
1115 if (event_glob != NULL && !strglobmatch(name, event_glob)) 1149 if (event_glob != NULL && !strglobmatch(name, event_glob))
1116 continue; 1150 continue;
1117 1151
1152 if (!is_event_supported(PERF_TYPE_HW_CACHE,
1153 type | (op << 8) | (i << 16)))
1154 continue;
1155
1118 if (name_only) 1156 if (name_only)
1119 printf("%s ", name); 1157 printf("%s ", name);
1120 else 1158 else
@@ -1144,6 +1182,9 @@ static void print_symbol_events(const char *event_glob, unsigned type,
1144 (syms->alias && strglobmatch(syms->alias, event_glob)))) 1182 (syms->alias && strglobmatch(syms->alias, event_glob))))
1145 continue; 1183 continue;
1146 1184
1185 if (!is_event_supported(type, i))
1186 continue;
1187
1147 if (name_only) { 1188 if (name_only) {
1148 printf("%s ", syms->symbol); 1189 printf("%s ", syms->symbol);
1149 continue; 1190 continue;
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 0790452658b3..91346b753960 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -145,6 +145,7 @@ context-switches|cs { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW
145cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); } 145cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
146alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); } 146alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
147emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); } 147emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
148dummy { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); }
148 149
149L1-dcache|l1-d|l1d|L1-data | 150L1-dcache|l1-d|l1d|L1-data |
150L1-icache|l1-i|l1i|L1-instruction | 151L1-icache|l1-i|l1i|L1-instruction |
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 381f4fda9654..71b5412bbbb9 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -987,6 +987,7 @@ static struct {
987 { "COUNT_SW_PAGE_FAULTS_MAJ", PERF_COUNT_SW_PAGE_FAULTS_MAJ }, 987 { "COUNT_SW_PAGE_FAULTS_MAJ", PERF_COUNT_SW_PAGE_FAULTS_MAJ },
988 { "COUNT_SW_ALIGNMENT_FAULTS", PERF_COUNT_SW_ALIGNMENT_FAULTS }, 988 { "COUNT_SW_ALIGNMENT_FAULTS", PERF_COUNT_SW_ALIGNMENT_FAULTS },
989 { "COUNT_SW_EMULATION_FAULTS", PERF_COUNT_SW_EMULATION_FAULTS }, 989 { "COUNT_SW_EMULATION_FAULTS", PERF_COUNT_SW_EMULATION_FAULTS },
990 { "COUNT_SW_DUMMY", PERF_COUNT_SW_DUMMY },
990 991
991 { "SAMPLE_IP", PERF_SAMPLE_IP }, 992 { "SAMPLE_IP", PERF_SAMPLE_IP },
992 { "SAMPLE_TID", PERF_SAMPLE_TID }, 993 { "SAMPLE_TID", PERF_SAMPLE_TID },
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 07642a7b9346..1fc0c628683e 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1513,6 +1513,7 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
1513 printf(" "); 1513 printf(" ");
1514 if (print_symoffset) { 1514 if (print_symoffset) {
1515 al.addr = node->ip; 1515 al.addr = node->ip;
1516 al.map = node->map;
1516 symbol__fprintf_symname_offs(node->sym, &al, stdout); 1517 symbol__fprintf_symname_offs(node->sym, &al, stdout);
1517 } else 1518 } else
1518 symbol__fprintf_symname(node->sym, stdout); 1519 symbol__fprintf_symname(node->sym, stdout);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 77f3b95bb46d..7eb0362f4ffd 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -259,7 +259,10 @@ size_t symbol__fprintf_symname_offs(const struct symbol *sym,
259 if (sym && sym->name) { 259 if (sym && sym->name) {
260 length = fprintf(fp, "%s", sym->name); 260 length = fprintf(fp, "%s", sym->name);
261 if (al) { 261 if (al) {
262 offset = al->addr - sym->start; 262 if (al->addr < sym->end)
263 offset = al->addr - sym->start;
264 else
265 offset = al->addr - al->map->start - sym->start;
263 length += fprintf(fp, "+0x%lx", offset); 266 length += fprintf(fp, "+0x%lx", offset);
264 } 267 }
265 return length; 268 return length;