aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;