aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2016-05-31 03:24:10 -0400
committerIngo Molnar <mingo@kernel.org>2016-05-31 03:24:10 -0400
commit42c4fb774782eead571f7379edf16b1138e7cebb (patch)
tree5c4402acae1302df82e146809e3193459b338556
parent711460514b1c80494f14001bdf30dd70fd401a8f (diff)
parent01412261d99497021353c4b1d67e8df6c9cdc3c6 (diff)
Merge tag 'perf-core-for-mingo-20160530' 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: User visible/kernel ABI changes: - Per event callchain limit: Recently we introduced a sysctl to tune the max-stack for all events for which callchains were requested: $ sysctl kernel.perf_event_max_stack kernel.perf_event_max_stack = 127 Now this patch introduces a way to configure this per event, i.e. this becomes possible: $ perf record -e sched:*/max-stack=2/ -e block:*/max-stack=10/ -a allowing finer tuning of how much buffer space callchains use. This uses an u16 from the reserved space at the end, leaving another u16 for future use. There has been interest in even finer tuning, namely to control the max stack for kernel and userspace callchains separately. Further discussion is needed, we may for instance use the remaining u16 for that and when it is present, assume that the sample_max_stack introduced in this patch applies for the kernel, and the u16 left is used for limiting the userspace callchain. (Arnaldo Carvalho de Melo) Infrastructure changes: - Adopt get_main_thread from db-export.c (Andi Kleen) - More prep work for backward ring buffer support (Wang Nan) - Prep work for supporting SDT (Statically Defined Tracing) tracepoints (Masami Hiramatsu) - Add arch/*/include/generated/ to .gitignore (Taeung Song) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--include/linux/perf_event.h2
-rw-r--r--include/uapi/linux/perf_event.h6
-rw-r--r--kernel/bpf/stackmap.c2
-rw-r--r--kernel/events/callchain.c14
-rw-r--r--kernel/events/core.c5
-rw-r--r--tools/lib/api/fd/array.c5
-rw-r--r--tools/lib/api/fd/array.h3
-rw-r--r--tools/perf/.gitignore1
-rw-r--r--tools/perf/arch/x86/util/tsc.c2
-rw-r--r--tools/perf/builtin-record.c9
-rw-r--r--tools/perf/tests/fdarray.c8
-rw-r--r--tools/perf/util/build-id.c115
-rw-r--r--tools/perf/util/build-id.h2
-rw-r--r--tools/perf/util/callchain.h1
-rw-r--r--tools/perf/util/db-export.c13
-rw-r--r--tools/perf/util/dso.h5
-rw-r--r--tools/perf/util/evlist.c43
-rw-r--r--tools/perf/util/evlist.h2
-rw-r--r--tools/perf/util/evsel.c16
-rw-r--r--tools/perf/util/evsel.h2
-rw-r--r--tools/perf/util/parse-events.c8
-rw-r--r--tools/perf/util/parse-events.h1
-rw-r--r--tools/perf/util/parse-events.l1
-rw-r--r--tools/perf/util/session.c2
-rw-r--r--tools/perf/util/symbol.c71
-rw-r--r--tools/perf/util/thread.c11
-rw-r--r--tools/perf/util/thread.h2
27 files changed, 252 insertions, 100 deletions
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 6b87be908790..0e43355c7aad 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1076,7 +1076,7 @@ extern void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct
1076extern struct perf_callchain_entry * 1076extern struct perf_callchain_entry *
1077get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user, 1077get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user,
1078 u32 max_stack, bool crosstask, bool add_mark); 1078 u32 max_stack, bool crosstask, bool add_mark);
1079extern int get_callchain_buffers(void); 1079extern int get_callchain_buffers(int max_stack);
1080extern void put_callchain_buffers(void); 1080extern void put_callchain_buffers(void);
1081 1081
1082extern int sysctl_perf_event_max_stack; 1082extern int sysctl_perf_event_max_stack;
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 36ce552cf6a9..c66a485a24ac 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -276,6 +276,9 @@ enum perf_event_read_format {
276 276
277/* 277/*
278 * Hardware event_id to monitor via a performance monitoring event: 278 * Hardware event_id to monitor via a performance monitoring event:
279 *
280 * @sample_max_stack: Max number of frame pointers in a callchain,
281 * should be < /proc/sys/kernel/perf_event_max_stack
279 */ 282 */
280struct perf_event_attr { 283struct perf_event_attr {
281 284
@@ -385,7 +388,8 @@ struct perf_event_attr {
385 * Wakeup watermark for AUX area 388 * Wakeup watermark for AUX area
386 */ 389 */
387 __u32 aux_watermark; 390 __u32 aux_watermark;
388 __u32 __reserved_2; /* align to __u64 */ 391 __u16 sample_max_stack;
392 __u16 __reserved_2; /* align to __u64 */
389}; 393};
390 394
391#define perf_flags(attr) (*(&(attr)->read_format + 1)) 395#define perf_flags(attr) (*(&(attr)->read_format + 1))
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index a82d7605db3f..f1de5c1a2af6 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -99,7 +99,7 @@ static struct bpf_map *stack_map_alloc(union bpf_attr *attr)
99 if (err) 99 if (err)
100 goto free_smap; 100 goto free_smap;
101 101
102 err = get_callchain_buffers(); 102 err = get_callchain_buffers(sysctl_perf_event_max_stack);
103 if (err) 103 if (err)
104 goto free_smap; 104 goto free_smap;
105 105
diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
index 179ef4640964..e9fdb5203de5 100644
--- a/kernel/events/callchain.c
+++ b/kernel/events/callchain.c
@@ -104,7 +104,7 @@ fail:
104 return -ENOMEM; 104 return -ENOMEM;
105} 105}
106 106
107int get_callchain_buffers(void) 107int get_callchain_buffers(int event_max_stack)
108{ 108{
109 int err = 0; 109 int err = 0;
110 int count; 110 int count;
@@ -121,6 +121,15 @@ int get_callchain_buffers(void)
121 /* If the allocation failed, give up */ 121 /* If the allocation failed, give up */
122 if (!callchain_cpus_entries) 122 if (!callchain_cpus_entries)
123 err = -ENOMEM; 123 err = -ENOMEM;
124 /*
125 * If requesting per event more than the global cap,
126 * return a different error to help userspace figure
127 * this out.
128 *
129 * And also do it here so that we have &callchain_mutex held.
130 */
131 if (event_max_stack > sysctl_perf_event_max_stack)
132 err = -EOVERFLOW;
124 goto exit; 133 goto exit;
125 } 134 }
126 135
@@ -174,11 +183,12 @@ perf_callchain(struct perf_event *event, struct pt_regs *regs)
174 bool user = !event->attr.exclude_callchain_user; 183 bool user = !event->attr.exclude_callchain_user;
175 /* Disallow cross-task user callchains. */ 184 /* Disallow cross-task user callchains. */
176 bool crosstask = event->ctx->task && event->ctx->task != current; 185 bool crosstask = event->ctx->task && event->ctx->task != current;
186 const u32 max_stack = event->attr.sample_max_stack;
177 187
178 if (!kernel && !user) 188 if (!kernel && !user)
179 return NULL; 189 return NULL;
180 190
181 return get_perf_callchain(regs, 0, kernel, user, sysctl_perf_event_max_stack, crosstask, true); 191 return get_perf_callchain(regs, 0, kernel, user, max_stack, crosstask, true);
182} 192}
183 193
184struct perf_callchain_entry * 194struct perf_callchain_entry *
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 050a290c72c7..79363f298445 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -8843,7 +8843,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
8843 8843
8844 if (!event->parent) { 8844 if (!event->parent) {
8845 if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN) { 8845 if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN) {
8846 err = get_callchain_buffers(); 8846 err = get_callchain_buffers(attr->sample_max_stack);
8847 if (err) 8847 if (err)
8848 goto err_addr_filters; 8848 goto err_addr_filters;
8849 } 8849 }
@@ -9165,6 +9165,9 @@ SYSCALL_DEFINE5(perf_event_open,
9165 return -EINVAL; 9165 return -EINVAL;
9166 } 9166 }
9167 9167
9168 if (!attr.sample_max_stack)
9169 attr.sample_max_stack = sysctl_perf_event_max_stack;
9170
9168 /* 9171 /*
9169 * In cgroup mode, the pid argument is used to pass the fd 9172 * In cgroup mode, the pid argument is used to pass the fd
9170 * opened to the cgroup directory in cgroupfs. The cpu argument 9173 * opened to the cgroup directory in cgroupfs. The cpu argument
diff --git a/tools/lib/api/fd/array.c b/tools/lib/api/fd/array.c
index 0e636c4339b8..b0a035fc87b3 100644
--- a/tools/lib/api/fd/array.c
+++ b/tools/lib/api/fd/array.c
@@ -85,7 +85,8 @@ int fdarray__add(struct fdarray *fda, int fd, short revents)
85} 85}
86 86
87int fdarray__filter(struct fdarray *fda, short revents, 87int fdarray__filter(struct fdarray *fda, short revents,
88 void (*entry_destructor)(struct fdarray *fda, int fd)) 88 void (*entry_destructor)(struct fdarray *fda, int fd, void *arg),
89 void *arg)
89{ 90{
90 int fd, nr = 0; 91 int fd, nr = 0;
91 92
@@ -95,7 +96,7 @@ int fdarray__filter(struct fdarray *fda, short revents,
95 for (fd = 0; fd < fda->nr; ++fd) { 96 for (fd = 0; fd < fda->nr; ++fd) {
96 if (fda->entries[fd].revents & revents) { 97 if (fda->entries[fd].revents & revents) {
97 if (entry_destructor) 98 if (entry_destructor)
98 entry_destructor(fda, fd); 99 entry_destructor(fda, fd, arg);
99 100
100 continue; 101 continue;
101 } 102 }
diff --git a/tools/lib/api/fd/array.h b/tools/lib/api/fd/array.h
index 45db01818f45..e87fd800fa8d 100644
--- a/tools/lib/api/fd/array.h
+++ b/tools/lib/api/fd/array.h
@@ -34,7 +34,8 @@ void fdarray__delete(struct fdarray *fda);
34int fdarray__add(struct fdarray *fda, int fd, short revents); 34int fdarray__add(struct fdarray *fda, int fd, short revents);
35int fdarray__poll(struct fdarray *fda, int timeout); 35int fdarray__poll(struct fdarray *fda, int timeout);
36int fdarray__filter(struct fdarray *fda, short revents, 36int fdarray__filter(struct fdarray *fda, short revents,
37 void (*entry_destructor)(struct fdarray *fda, int fd)); 37 void (*entry_destructor)(struct fdarray *fda, int fd, void *arg),
38 void *arg);
38int fdarray__grow(struct fdarray *fda, int extra); 39int fdarray__grow(struct fdarray *fda, int extra);
39int fdarray__fprintf(struct fdarray *fda, FILE *fp); 40int fdarray__fprintf(struct fdarray *fda, FILE *fp);
40 41
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index 3d1bb802dbf4..3db3db9278be 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -30,3 +30,4 @@ config.mak.autogen
30*.pyo 30*.pyo
31.config-detected 31.config-detected
32util/intel-pt-decoder/inat-tables.c 32util/intel-pt-decoder/inat-tables.c
33arch/*/include/generated/
diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c
index 357f1b13b5ae..2e5567c94e09 100644
--- a/tools/perf/arch/x86/util/tsc.c
+++ b/tools/perf/arch/x86/util/tsc.c
@@ -62,6 +62,8 @@ int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc,
62 struct perf_tsc_conversion tc; 62 struct perf_tsc_conversion tc;
63 int err; 63 int err;
64 64
65 if (!pc)
66 return 0;
65 err = perf_read_tsc_conversion(pc, &tc); 67 err = perf_read_tsc_conversion(pc, &tc);
66 if (err == -EOPNOTSUPP) 68 if (err == -EOPNOTSUPP)
67 return 0; 69 return 0;
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index dc3fcb597e4c..d4cf1b0c88f9 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -655,6 +655,13 @@ perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused
655 return 0; 655 return 0;
656} 656}
657 657
658static const struct perf_event_mmap_page *record__pick_pc(struct record *rec)
659{
660 if (rec->evlist && rec->evlist->mmap && rec->evlist->mmap[0].base)
661 return rec->evlist->mmap[0].base;
662 return NULL;
663}
664
658static int record__synthesize(struct record *rec) 665static int record__synthesize(struct record *rec)
659{ 666{
660 struct perf_session *session = rec->session; 667 struct perf_session *session = rec->session;
@@ -692,7 +699,7 @@ static int record__synthesize(struct record *rec)
692 } 699 }
693 } 700 }
694 701
695 err = perf_event__synth_time_conv(rec->evlist->mmap[0].base, tool, 702 err = perf_event__synth_time_conv(record__pick_pc(rec), tool,
696 process_synthesized_event, machine); 703 process_synthesized_event, machine);
697 if (err) 704 if (err)
698 goto out; 705 goto out;
diff --git a/tools/perf/tests/fdarray.c b/tools/perf/tests/fdarray.c
index c809463edbe5..59dbd0550c51 100644
--- a/tools/perf/tests/fdarray.c
+++ b/tools/perf/tests/fdarray.c
@@ -36,7 +36,7 @@ int test__fdarray__filter(int subtest __maybe_unused)
36 } 36 }
37 37
38 fdarray__init_revents(fda, POLLIN); 38 fdarray__init_revents(fda, POLLIN);
39 nr_fds = fdarray__filter(fda, POLLHUP, NULL); 39 nr_fds = fdarray__filter(fda, POLLHUP, NULL, NULL);
40 if (nr_fds != fda->nr_alloc) { 40 if (nr_fds != fda->nr_alloc) {
41 pr_debug("\nfdarray__filter()=%d != %d shouldn't have filtered anything", 41 pr_debug("\nfdarray__filter()=%d != %d shouldn't have filtered anything",
42 nr_fds, fda->nr_alloc); 42 nr_fds, fda->nr_alloc);
@@ -44,7 +44,7 @@ int test__fdarray__filter(int subtest __maybe_unused)
44 } 44 }
45 45
46 fdarray__init_revents(fda, POLLHUP); 46 fdarray__init_revents(fda, POLLHUP);
47 nr_fds = fdarray__filter(fda, POLLHUP, NULL); 47 nr_fds = fdarray__filter(fda, POLLHUP, NULL, NULL);
48 if (nr_fds != 0) { 48 if (nr_fds != 0) {
49 pr_debug("\nfdarray__filter()=%d != %d, should have filtered all fds", 49 pr_debug("\nfdarray__filter()=%d != %d, should have filtered all fds",
50 nr_fds, fda->nr_alloc); 50 nr_fds, fda->nr_alloc);
@@ -57,7 +57,7 @@ int test__fdarray__filter(int subtest __maybe_unused)
57 57
58 pr_debug("\nfiltering all but fda->entries[2]:"); 58 pr_debug("\nfiltering all but fda->entries[2]:");
59 fdarray__fprintf_prefix(fda, "before", stderr); 59 fdarray__fprintf_prefix(fda, "before", stderr);
60 nr_fds = fdarray__filter(fda, POLLHUP, NULL); 60 nr_fds = fdarray__filter(fda, POLLHUP, NULL, NULL);
61 fdarray__fprintf_prefix(fda, " after", stderr); 61 fdarray__fprintf_prefix(fda, " after", stderr);
62 if (nr_fds != 1) { 62 if (nr_fds != 1) {
63 pr_debug("\nfdarray__filter()=%d != 1, should have left just one event", nr_fds); 63 pr_debug("\nfdarray__filter()=%d != 1, should have left just one event", nr_fds);
@@ -78,7 +78,7 @@ int test__fdarray__filter(int subtest __maybe_unused)
78 78
79 pr_debug("\nfiltering all but (fda->entries[0], fda->entries[3]):"); 79 pr_debug("\nfiltering all but (fda->entries[0], fda->entries[3]):");
80 fdarray__fprintf_prefix(fda, "before", stderr); 80 fdarray__fprintf_prefix(fda, "before", stderr);
81 nr_fds = fdarray__filter(fda, POLLHUP, NULL); 81 nr_fds = fdarray__filter(fda, POLLHUP, NULL, NULL);
82 fdarray__fprintf_prefix(fda, " after", stderr); 82 fdarray__fprintf_prefix(fda, " after", stderr);
83 if (nr_fds != 2) { 83 if (nr_fds != 2) {
84 pr_debug("\nfdarray__filter()=%d != 2, should have left just two events", 84 pr_debug("\nfdarray__filter()=%d != 2, should have left just two events",
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 67e5966503b2..67f986c8c378 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -144,7 +144,32 @@ static int asnprintf(char **strp, size_t size, const char *fmt, ...)
144 return ret; 144 return ret;
145} 145}
146 146
147static char *build_id__filename(const char *sbuild_id, char *bf, size_t size) 147char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf,
148 size_t size)
149{
150 bool is_alloc = !!bf;
151 bool retry_old = true;
152
153 asnprintf(&bf, size, "%s/%s/%s/kallsyms",
154 buildid_dir, DSO__NAME_KALLSYMS, sbuild_id);
155retry:
156 if (!access(bf, F_OK))
157 return bf;
158 if (is_alloc)
159 free(bf);
160 if (retry_old) {
161 /* Try old style kallsyms cache */
162 asnprintf(&bf, size, "%s/%s/%s",
163 buildid_dir, DSO__NAME_KALLSYMS, sbuild_id);
164 retry_old = false;
165 goto retry;
166 }
167
168 return NULL;
169}
170
171static char *build_id_cache__linkname(const char *sbuild_id, char *bf,
172 size_t size)
148{ 173{
149 char *tmp = bf; 174 char *tmp = bf;
150 int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir, 175 int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
@@ -154,23 +179,52 @@ static char *build_id__filename(const char *sbuild_id, char *bf, size_t size)
154 return bf; 179 return bf;
155} 180}
156 181
182static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
183{
184 return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
185}
186
157char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size) 187char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
158{ 188{
159 char build_id_hex[SBUILD_ID_SIZE]; 189 bool is_kallsyms = dso__is_kallsyms((struct dso *)dso);
190 bool is_vdso = dso__is_vdso((struct dso *)dso);
191 char sbuild_id[SBUILD_ID_SIZE];
192 char *linkname;
193 bool alloc = (bf == NULL);
194 int ret;
160 195
161 if (!dso->has_build_id) 196 if (!dso->has_build_id)
162 return NULL; 197 return NULL;
163 198
164 build_id__sprintf(dso->build_id, sizeof(dso->build_id), build_id_hex); 199 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
165 return build_id__filename(build_id_hex, bf, size); 200 linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
201 if (!linkname)
202 return NULL;
203
204 /* Check if old style build_id cache */
205 if (is_regular_file(linkname))
206 ret = asnprintf(&bf, size, "%s", linkname);
207 else
208 ret = asnprintf(&bf, size, "%s/%s", linkname,
209 build_id_cache__basename(is_kallsyms, is_vdso));
210 if (ret < 0 || (!alloc && size < (unsigned int)ret))
211 bf = NULL;
212 free(linkname);
213
214 return bf;
166} 215}
167 216
168bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size) 217bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size)
169{ 218{
170 char *id_name, *ch; 219 char *id_name = NULL, *ch;
171 struct stat sb; 220 struct stat sb;
221 char sbuild_id[SBUILD_ID_SIZE];
222
223 if (!dso->has_build_id)
224 goto err;
172 225
173 id_name = dso__build_id_filename(dso, bf, size); 226 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
227 id_name = build_id_cache__linkname(sbuild_id, NULL, 0);
174 if (!id_name) 228 if (!id_name)
175 goto err; 229 goto err;
176 if (access(id_name, F_OK)) 230 if (access(id_name, F_OK))
@@ -194,18 +248,14 @@ bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size)
194 if (ch - 3 < bf) 248 if (ch - 3 < bf)
195 goto err; 249 goto err;
196 250
251 free(id_name);
197 return strncmp(".ko", ch - 3, 3) == 0; 252 return strncmp(".ko", ch - 3, 3) == 0;
198err: 253err:
199 /*
200 * If dso__build_id_filename work, get id_name again,
201 * because id_name points to bf and is broken.
202 */
203 if (id_name)
204 id_name = dso__build_id_filename(dso, bf, size);
205 pr_err("Invalid build id: %s\n", id_name ? : 254 pr_err("Invalid build id: %s\n", id_name ? :
206 dso->long_name ? : 255 dso->long_name ? :
207 dso->short_name ? : 256 dso->short_name ? :
208 "[unknown]"); 257 "[unknown]");
258 free(id_name);
209 return false; 259 return false;
210} 260}
211 261
@@ -341,7 +391,8 @@ void disable_buildid_cache(void)
341} 391}
342 392
343static char *build_id_cache__dirname_from_path(const char *name, 393static char *build_id_cache__dirname_from_path(const char *name,
344 bool is_kallsyms, bool is_vdso) 394 bool is_kallsyms, bool is_vdso,
395 const char *sbuild_id)
345{ 396{
346 char *realname = (char *)name, *filename; 397 char *realname = (char *)name, *filename;
347 bool slash = is_kallsyms || is_vdso; 398 bool slash = is_kallsyms || is_vdso;
@@ -352,8 +403,9 @@ static char *build_id_cache__dirname_from_path(const char *name,
352 return NULL; 403 return NULL;
353 } 404 }
354 405
355 if (asprintf(&filename, "%s%s%s", buildid_dir, slash ? "/" : "", 406 if (asprintf(&filename, "%s%s%s%s%s", buildid_dir, slash ? "/" : "",
356 is_vdso ? DSO__NAME_VDSO : realname) < 0) 407 is_vdso ? DSO__NAME_VDSO : realname,
408 sbuild_id ? "/" : "", sbuild_id ?: "") < 0)
357 filename = NULL; 409 filename = NULL;
358 410
359 if (!slash) 411 if (!slash)
@@ -368,7 +420,8 @@ int build_id_cache__list_build_ids(const char *pathname,
368 char *dir_name; 420 char *dir_name;
369 int ret = 0; 421 int ret = 0;
370 422
371 dir_name = build_id_cache__dirname_from_path(pathname, false, false); 423 dir_name = build_id_cache__dirname_from_path(pathname, false, false,
424 NULL);
372 if (!dir_name) 425 if (!dir_name)
373 return -ENOMEM; 426 return -ENOMEM;
374 427
@@ -385,7 +438,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
385{ 438{
386 const size_t size = PATH_MAX; 439 const size_t size = PATH_MAX;
387 char *realname = NULL, *filename = NULL, *dir_name = NULL, 440 char *realname = NULL, *filename = NULL, *dir_name = NULL,
388 *linkname = zalloc(size), *targetname, *tmp; 441 *linkname = zalloc(size), *tmp;
389 int err = -1; 442 int err = -1;
390 443
391 if (!is_kallsyms) { 444 if (!is_kallsyms) {
@@ -394,14 +447,22 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
394 goto out_free; 447 goto out_free;
395 } 448 }
396 449
397 dir_name = build_id_cache__dirname_from_path(name, is_kallsyms, is_vdso); 450 dir_name = build_id_cache__dirname_from_path(name, is_kallsyms,
451 is_vdso, sbuild_id);
398 if (!dir_name) 452 if (!dir_name)
399 goto out_free; 453 goto out_free;
400 454
455 /* Remove old style build-id cache */
456 if (is_regular_file(dir_name))
457 if (unlink(dir_name))
458 goto out_free;
459
401 if (mkdir_p(dir_name, 0755)) 460 if (mkdir_p(dir_name, 0755))
402 goto out_free; 461 goto out_free;
403 462
404 if (asprintf(&filename, "%s/%s", dir_name, sbuild_id) < 0) { 463 /* Save the allocated buildid dirname */
464 if (asprintf(&filename, "%s/%s", dir_name,
465 build_id_cache__basename(is_kallsyms, is_vdso)) < 0) {
405 filename = NULL; 466 filename = NULL;
406 goto out_free; 467 goto out_free;
407 } 468 }
@@ -415,7 +476,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
415 goto out_free; 476 goto out_free;
416 } 477 }
417 478
418 if (!build_id__filename(sbuild_id, linkname, size)) 479 if (!build_id_cache__linkname(sbuild_id, linkname, size))
419 goto out_free; 480 goto out_free;
420 tmp = strrchr(linkname, '/'); 481 tmp = strrchr(linkname, '/');
421 *tmp = '\0'; 482 *tmp = '\0';
@@ -424,10 +485,10 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
424 goto out_free; 485 goto out_free;
425 486
426 *tmp = '/'; 487 *tmp = '/';
427 targetname = filename + strlen(buildid_dir) - 5; 488 tmp = dir_name + strlen(buildid_dir) - 5;
428 memcpy(targetname, "../..", 5); 489 memcpy(tmp, "../..", 5);
429 490
430 if (symlink(targetname, linkname) == 0) 491 if (symlink(tmp, linkname) == 0)
431 err = 0; 492 err = 0;
432out_free: 493out_free:
433 if (!is_kallsyms) 494 if (!is_kallsyms)
@@ -452,7 +513,7 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
452bool build_id_cache__cached(const char *sbuild_id) 513bool build_id_cache__cached(const char *sbuild_id)
453{ 514{
454 bool ret = false; 515 bool ret = false;
455 char *filename = build_id__filename(sbuild_id, NULL, 0); 516 char *filename = build_id_cache__linkname(sbuild_id, NULL, 0);
456 517
457 if (filename && !access(filename, F_OK)) 518 if (filename && !access(filename, F_OK))
458 ret = true; 519 ret = true;
@@ -471,7 +532,7 @@ int build_id_cache__remove_s(const char *sbuild_id)
471 if (filename == NULL || linkname == NULL) 532 if (filename == NULL || linkname == NULL)
472 goto out_free; 533 goto out_free;
473 534
474 if (!build_id__filename(sbuild_id, linkname, size)) 535 if (!build_id_cache__linkname(sbuild_id, linkname, size))
475 goto out_free; 536 goto out_free;
476 537
477 if (access(linkname, F_OK)) 538 if (access(linkname, F_OK))
@@ -489,7 +550,7 @@ int build_id_cache__remove_s(const char *sbuild_id)
489 tmp = strrchr(linkname, '/') + 1; 550 tmp = strrchr(linkname, '/') + 1;
490 snprintf(tmp, size - (tmp - linkname), "%s", filename); 551 snprintf(tmp, size - (tmp - linkname), "%s", filename);
491 552
492 if (unlink(linkname)) 553 if (rm_rf(linkname))
493 goto out_free; 554 goto out_free;
494 555
495 err = 0; 556 err = 0;
@@ -501,7 +562,7 @@ out_free:
501 562
502static int dso__cache_build_id(struct dso *dso, struct machine *machine) 563static int dso__cache_build_id(struct dso *dso, struct machine *machine)
503{ 564{
504 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; 565 bool is_kallsyms = dso__is_kallsyms(dso);
505 bool is_vdso = dso__is_vdso(dso); 566 bool is_vdso = dso__is_vdso(dso);
506 const char *name = dso->long_name; 567 const char *name = dso->long_name;
507 char nm[PATH_MAX]; 568 char nm[PATH_MAX];
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index 64af3e20610d..e5435f46e48e 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -14,6 +14,8 @@ struct dso;
14int build_id__sprintf(const u8 *build_id, int len, char *bf); 14int build_id__sprintf(const u8 *build_id, int len, char *bf);
15int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id); 15int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id);
16int filename__sprintf_build_id(const char *pathname, char *sbuild_id); 16int filename__sprintf_build_id(const char *pathname, char *sbuild_id);
17char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf,
18 size_t size);
17 19
18char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size); 20char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
19bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size); 21bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size);
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 65e2a4f7cb4e..a70f6b54eb92 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -94,6 +94,7 @@ struct callchain_param {
94 enum perf_call_graph_mode record_mode; 94 enum perf_call_graph_mode record_mode;
95 u32 dump_size; 95 u32 dump_size;
96 enum chain_mode mode; 96 enum chain_mode mode;
97 u16 max_stack;
97 u32 print_limit; 98 u32 print_limit;
98 double min_percent; 99 double min_percent;
99 sort_chain_func_t sort; 100 sort_chain_func_t sort;
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c
index c9a6dc173e74..b0c2b5c5d337 100644
--- a/tools/perf/util/db-export.c
+++ b/tools/perf/util/db-export.c
@@ -233,17 +233,6 @@ int db_export__symbol(struct db_export *dbe, struct symbol *sym,
233 return 0; 233 return 0;
234} 234}
235 235
236static struct thread *get_main_thread(struct machine *machine, struct thread *thread)
237{
238 if (thread->pid_ == thread->tid)
239 return thread__get(thread);
240
241 if (thread->pid_ == -1)
242 return NULL;
243
244 return machine__find_thread(machine, thread->pid_, thread->pid_);
245}
246
247static int db_ids_from_al(struct db_export *dbe, struct addr_location *al, 236static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
248 u64 *dso_db_id, u64 *sym_db_id, u64 *offset) 237 u64 *dso_db_id, u64 *sym_db_id, u64 *offset)
249{ 238{
@@ -382,7 +371,7 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,
382 if (err) 371 if (err)
383 return err; 372 return err;
384 373
385 main_thread = get_main_thread(al->machine, thread); 374 main_thread = thread__main_thread(al->machine, thread);
386 if (main_thread) 375 if (main_thread)
387 comm = machine__thread_exec_comm(al->machine, main_thread); 376 comm = machine__thread_exec_comm(al->machine, main_thread);
388 377
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 0953280629cf..76d79d070e21 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -349,6 +349,11 @@ static inline bool dso__is_kcore(struct dso *dso)
349 dso->binary_type == DSO_BINARY_TYPE__GUEST_KCORE; 349 dso->binary_type == DSO_BINARY_TYPE__GUEST_KCORE;
350} 350}
351 351
352static inline bool dso__is_kallsyms(struct dso *dso)
353{
354 return dso->kernel && dso->long_name[0] != '/';
355}
356
352void dso__free_a2l(struct dso *dso); 357void dso__free_a2l(struct dso *dso);
353 358
354enum dso_type dso__type(struct dso *dso, struct machine *machine); 359enum dso_type dso__type(struct dso *dso, struct machine *machine);
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index e82ba90cc969..e0f30946ed1a 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -462,9 +462,9 @@ int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
462 return 0; 462 return 0;
463} 463}
464 464
465static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, int idx) 465static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, int idx, short revent)
466{ 466{
467 int pos = fdarray__add(&evlist->pollfd, fd, POLLIN | POLLERR | POLLHUP); 467 int pos = fdarray__add(&evlist->pollfd, fd, revent | POLLERR | POLLHUP);
468 /* 468 /*
469 * Save the idx so that when we filter out fds POLLHUP'ed we can 469 * Save the idx so that when we filter out fds POLLHUP'ed we can
470 * close the associated evlist->mmap[] entry. 470 * close the associated evlist->mmap[] entry.
@@ -480,10 +480,11 @@ static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, int idx
480 480
481int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd) 481int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd)
482{ 482{
483 return __perf_evlist__add_pollfd(evlist, fd, -1); 483 return __perf_evlist__add_pollfd(evlist, fd, -1, POLLIN);
484} 484}
485 485
486static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd) 486static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd,
487 void *arg __maybe_unused)
487{ 488{
488 struct perf_evlist *evlist = container_of(fda, struct perf_evlist, pollfd); 489 struct perf_evlist *evlist = container_of(fda, struct perf_evlist, pollfd);
489 490
@@ -493,7 +494,7 @@ static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd)
493int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask) 494int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask)
494{ 495{
495 return fdarray__filter(&evlist->pollfd, revents_and_mask, 496 return fdarray__filter(&evlist->pollfd, revents_and_mask,
496 perf_evlist__munmap_filtered); 497 perf_evlist__munmap_filtered, NULL);
497} 498}
498 499
499int perf_evlist__poll(struct perf_evlist *evlist, int timeout) 500int perf_evlist__poll(struct perf_evlist *evlist, int timeout)
@@ -777,7 +778,7 @@ broken_event:
777 return event; 778 return event;
778} 779}
779 780
780union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) 781union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist, int idx)
781{ 782{
782 struct perf_mmap *md = &evlist->mmap[idx]; 783 struct perf_mmap *md = &evlist->mmap[idx];
783 u64 head; 784 u64 head;
@@ -832,6 +833,13 @@ perf_evlist__mmap_read_backward(struct perf_evlist *evlist, int idx)
832 return perf_mmap__read(md, false, start, end, &md->prev); 833 return perf_mmap__read(md, false, start, end, &md->prev);
833} 834}
834 835
836union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
837{
838 if (!evlist->backward)
839 return perf_evlist__mmap_read_forward(evlist, idx);
840 return perf_evlist__mmap_read_backward(evlist, idx);
841}
842
835void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx) 843void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx)
836{ 844{
837 struct perf_mmap *md = &evlist->mmap[idx]; 845 struct perf_mmap *md = &evlist->mmap[idx];
@@ -856,9 +864,11 @@ static void perf_evlist__mmap_get(struct perf_evlist *evlist, int idx)
856 864
857static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx) 865static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx)
858{ 866{
859 BUG_ON(atomic_read(&evlist->mmap[idx].refcnt) == 0); 867 struct perf_mmap *md = &evlist->mmap[idx];
860 868
861 if (atomic_dec_and_test(&evlist->mmap[idx].refcnt)) 869 BUG_ON(md->base && atomic_read(&md->refcnt) == 0);
870
871 if (atomic_dec_and_test(&md->refcnt))
862 __perf_evlist__munmap(evlist, idx); 872 __perf_evlist__munmap(evlist, idx);
863} 873}
864 874
@@ -983,15 +993,28 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
983 return 0; 993 return 0;
984} 994}
985 995
996static bool
997perf_evlist__should_poll(struct perf_evlist *evlist __maybe_unused,
998 struct perf_evsel *evsel)
999{
1000 if (evsel->overwrite)
1001 return false;
1002 return true;
1003}
1004
986static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, 1005static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
987 struct mmap_params *mp, int cpu, 1006 struct mmap_params *mp, int cpu,
988 int thread, int *output) 1007 int thread, int *output)
989{ 1008{
990 struct perf_evsel *evsel; 1009 struct perf_evsel *evsel;
1010 int revent;
991 1011
992 evlist__for_each(evlist, evsel) { 1012 evlist__for_each(evlist, evsel) {
993 int fd; 1013 int fd;
994 1014
1015 if (evsel->overwrite != (evlist->overwrite && evlist->backward))
1016 continue;
1017
995 if (evsel->system_wide && thread) 1018 if (evsel->system_wide && thread)
996 continue; 1019 continue;
997 1020
@@ -1008,6 +1031,8 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
1008 perf_evlist__mmap_get(evlist, idx); 1031 perf_evlist__mmap_get(evlist, idx);
1009 } 1032 }
1010 1033
1034 revent = perf_evlist__should_poll(evlist, evsel) ? POLLIN : 0;
1035
1011 /* 1036 /*
1012 * The system_wide flag causes a selected event to be opened 1037 * The system_wide flag causes a selected event to be opened
1013 * always without a pid. Consequently it will never get a 1038 * always without a pid. Consequently it will never get a
@@ -1016,7 +1041,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
1016 * Therefore don't add it for polling. 1041 * Therefore don't add it for polling.
1017 */ 1042 */
1018 if (!evsel->system_wide && 1043 if (!evsel->system_wide &&
1019 __perf_evlist__add_pollfd(evlist, fd, idx) < 0) { 1044 __perf_evlist__add_pollfd(evlist, fd, idx, revent) < 0) {
1020 perf_evlist__mmap_put(evlist, idx); 1045 perf_evlist__mmap_put(evlist, idx);
1021 return -1; 1046 return -1;
1022 } 1047 }
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index d740fb877ab6..68cb1361c97c 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -131,6 +131,8 @@ struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id);
131 131
132union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx); 132union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx);
133 133
134union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist,
135 int idx);
134union perf_event *perf_evlist__mmap_read_backward(struct perf_evlist *evlist, 136union perf_event *perf_evlist__mmap_read_backward(struct perf_evlist *evlist,
135 int idx); 137 int idx);
136void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx); 138void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 02c177d14c8d..245ac503f211 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -572,6 +572,8 @@ void perf_evsel__config_callchain(struct perf_evsel *evsel,
572 572
573 perf_evsel__set_sample_bit(evsel, CALLCHAIN); 573 perf_evsel__set_sample_bit(evsel, CALLCHAIN);
574 574
575 attr->sample_max_stack = param->max_stack;
576
575 if (param->record_mode == CALLCHAIN_LBR) { 577 if (param->record_mode == CALLCHAIN_LBR) {
576 if (!opts->branch_stack) { 578 if (!opts->branch_stack) {
577 if (attr->exclude_user) { 579 if (attr->exclude_user) {
@@ -635,7 +637,8 @@ static void apply_config_terms(struct perf_evsel *evsel,
635 struct perf_event_attr *attr = &evsel->attr; 637 struct perf_event_attr *attr = &evsel->attr;
636 struct callchain_param param; 638 struct callchain_param param;
637 u32 dump_size = 0; 639 u32 dump_size = 0;
638 char *callgraph_buf = NULL; 640 int max_stack = 0;
641 const char *callgraph_buf = NULL;
639 642
640 /* callgraph default */ 643 /* callgraph default */
641 param.record_mode = callchain_param.record_mode; 644 param.record_mode = callchain_param.record_mode;
@@ -662,6 +665,9 @@ static void apply_config_terms(struct perf_evsel *evsel,
662 case PERF_EVSEL__CONFIG_TERM_STACK_USER: 665 case PERF_EVSEL__CONFIG_TERM_STACK_USER:
663 dump_size = term->val.stack_user; 666 dump_size = term->val.stack_user;
664 break; 667 break;
668 case PERF_EVSEL__CONFIG_TERM_MAX_STACK:
669 max_stack = term->val.max_stack;
670 break;
665 case PERF_EVSEL__CONFIG_TERM_INHERIT: 671 case PERF_EVSEL__CONFIG_TERM_INHERIT:
666 /* 672 /*
667 * attr->inherit should has already been set by 673 * attr->inherit should has already been set by
@@ -677,7 +683,12 @@ static void apply_config_terms(struct perf_evsel *evsel,
677 } 683 }
678 684
679 /* User explicitly set per-event callgraph, clear the old setting and reset. */ 685 /* User explicitly set per-event callgraph, clear the old setting and reset. */
680 if ((callgraph_buf != NULL) || (dump_size > 0)) { 686 if ((callgraph_buf != NULL) || (dump_size > 0) || max_stack) {
687 if (max_stack) {
688 param.max_stack = max_stack;
689 if (callgraph_buf == NULL)
690 callgraph_buf = "fp";
691 }
681 692
682 /* parse callgraph parameters */ 693 /* parse callgraph parameters */
683 if (callgraph_buf != NULL) { 694 if (callgraph_buf != NULL) {
@@ -1329,6 +1340,7 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr,
1329 PRINT_ATTRf(clockid, p_signed); 1340 PRINT_ATTRf(clockid, p_signed);
1330 PRINT_ATTRf(sample_regs_intr, p_hex); 1341 PRINT_ATTRf(sample_regs_intr, p_hex);
1331 PRINT_ATTRf(aux_watermark, p_unsigned); 1342 PRINT_ATTRf(aux_watermark, p_unsigned);
1343 PRINT_ATTRf(sample_max_stack, p_unsigned);
1332 1344
1333 return ret; 1345 return ret;
1334} 1346}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index c1f10159804c..028412b32d5a 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -44,6 +44,7 @@ enum {
44 PERF_EVSEL__CONFIG_TERM_CALLGRAPH, 44 PERF_EVSEL__CONFIG_TERM_CALLGRAPH,
45 PERF_EVSEL__CONFIG_TERM_STACK_USER, 45 PERF_EVSEL__CONFIG_TERM_STACK_USER,
46 PERF_EVSEL__CONFIG_TERM_INHERIT, 46 PERF_EVSEL__CONFIG_TERM_INHERIT,
47 PERF_EVSEL__CONFIG_TERM_MAX_STACK,
47 PERF_EVSEL__CONFIG_TERM_MAX, 48 PERF_EVSEL__CONFIG_TERM_MAX,
48}; 49};
49 50
@@ -56,6 +57,7 @@ struct perf_evsel_config_term {
56 bool time; 57 bool time;
57 char *callgraph; 58 char *callgraph;
58 u64 stack_user; 59 u64 stack_user;
60 int max_stack;
59 bool inherit; 61 bool inherit;
60 } val; 62 } val;
61}; 63};
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index bcbc983d4b12..89d40bb425e1 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -900,6 +900,7 @@ static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = {
900 [PARSE_EVENTS__TERM_TYPE_STACKSIZE] = "stack-size", 900 [PARSE_EVENTS__TERM_TYPE_STACKSIZE] = "stack-size",
901 [PARSE_EVENTS__TERM_TYPE_NOINHERIT] = "no-inherit", 901 [PARSE_EVENTS__TERM_TYPE_NOINHERIT] = "no-inherit",
902 [PARSE_EVENTS__TERM_TYPE_INHERIT] = "inherit", 902 [PARSE_EVENTS__TERM_TYPE_INHERIT] = "inherit",
903 [PARSE_EVENTS__TERM_TYPE_MAX_STACK] = "max-stack",
903}; 904};
904 905
905static bool config_term_shrinked; 906static bool config_term_shrinked;
@@ -995,6 +996,9 @@ do { \
995 case PARSE_EVENTS__TERM_TYPE_NAME: 996 case PARSE_EVENTS__TERM_TYPE_NAME:
996 CHECK_TYPE_VAL(STR); 997 CHECK_TYPE_VAL(STR);
997 break; 998 break;
999 case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
1000 CHECK_TYPE_VAL(NUM);
1001 break;
998 default: 1002 default:
999 err->str = strdup("unknown term"); 1003 err->str = strdup("unknown term");
1000 err->idx = term->err_term; 1004 err->idx = term->err_term;
@@ -1040,6 +1044,7 @@ static int config_term_tracepoint(struct perf_event_attr *attr,
1040 case PARSE_EVENTS__TERM_TYPE_STACKSIZE: 1044 case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
1041 case PARSE_EVENTS__TERM_TYPE_INHERIT: 1045 case PARSE_EVENTS__TERM_TYPE_INHERIT:
1042 case PARSE_EVENTS__TERM_TYPE_NOINHERIT: 1046 case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
1047 case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
1043 return config_term_common(attr, term, err); 1048 return config_term_common(attr, term, err);
1044 default: 1049 default:
1045 if (err) { 1050 if (err) {
@@ -1109,6 +1114,9 @@ do { \
1109 case PARSE_EVENTS__TERM_TYPE_NOINHERIT: 1114 case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
1110 ADD_CONFIG_TERM(INHERIT, inherit, term->val.num ? 0 : 1); 1115 ADD_CONFIG_TERM(INHERIT, inherit, term->val.num ? 0 : 1);
1111 break; 1116 break;
1117 case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
1118 ADD_CONFIG_TERM(MAX_STACK, max_stack, term->val.num);
1119 break;
1112 default: 1120 default:
1113 break; 1121 break;
1114 } 1122 }
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index d740c3ca9a1d..46c05ccd5dfe 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -68,6 +68,7 @@ enum {
68 PARSE_EVENTS__TERM_TYPE_STACKSIZE, 68 PARSE_EVENTS__TERM_TYPE_STACKSIZE,
69 PARSE_EVENTS__TERM_TYPE_NOINHERIT, 69 PARSE_EVENTS__TERM_TYPE_NOINHERIT,
70 PARSE_EVENTS__TERM_TYPE_INHERIT, 70 PARSE_EVENTS__TERM_TYPE_INHERIT,
71 PARSE_EVENTS__TERM_TYPE_MAX_STACK,
71 __PARSE_EVENTS__TERM_TYPE_NR, 72 __PARSE_EVENTS__TERM_TYPE_NR,
72}; 73};
73 74
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 1477fbc78993..01af1ee90a27 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -199,6 +199,7 @@ branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE
199time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); } 199time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); }
200call-graph { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CALLGRAPH); } 200call-graph { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CALLGRAPH); }
201stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); } 201stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); }
202max-stack { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_STACK); }
202inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); } 203inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); }
203no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } 204no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); }
204, { return ','; } 205, { return ','; }
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 2335b2824d8a..43d30ea87b7e 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -593,6 +593,7 @@ do { \
593 if (bswap_safe(f, 0)) \ 593 if (bswap_safe(f, 0)) \
594 attr->f = bswap_##sz(attr->f); \ 594 attr->f = bswap_##sz(attr->f); \
595} while(0) 595} while(0)
596#define bswap_field_16(f) bswap_field(f, 16)
596#define bswap_field_32(f) bswap_field(f, 32) 597#define bswap_field_32(f) bswap_field(f, 32)
597#define bswap_field_64(f) bswap_field(f, 64) 598#define bswap_field_64(f) bswap_field(f, 64)
598 599
@@ -608,6 +609,7 @@ do { \
608 bswap_field_64(sample_regs_user); 609 bswap_field_64(sample_regs_user);
609 bswap_field_32(sample_stack_user); 610 bswap_field_32(sample_stack_user);
610 bswap_field_32(aux_watermark); 611 bswap_field_32(aux_watermark);
612 bswap_field_16(sample_max_stack);
611 613
612 /* 614 /*
613 * After read_format are bitfields. Check read_format because 615 * After read_format are bitfields. Check read_format because
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 54c4ff2b1cee..09c5c34ae38d 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1641,6 +1641,20 @@ static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
1641 return ret; 1641 return ret;
1642} 1642}
1643 1643
1644/*
1645 * Use open(O_RDONLY) to check readability directly instead of access(R_OK)
1646 * since access(R_OK) only checks with real UID/GID but open() use effective
1647 * UID/GID and actual capabilities (e.g. /proc/kcore requires CAP_SYS_RAWIO).
1648 */
1649static bool filename__readable(const char *file)
1650{
1651 int fd = open(file, O_RDONLY);
1652 if (fd < 0)
1653 return false;
1654 close(fd);
1655 return true;
1656}
1657
1644static char *dso__find_kallsyms(struct dso *dso, struct map *map) 1658static char *dso__find_kallsyms(struct dso *dso, struct map *map)
1645{ 1659{
1646 u8 host_build_id[BUILD_ID_SIZE]; 1660 u8 host_build_id[BUILD_ID_SIZE];
@@ -1660,58 +1674,43 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
1660 sizeof(host_build_id)) == 0) 1674 sizeof(host_build_id)) == 0)
1661 is_host = dso__build_id_equal(dso, host_build_id); 1675 is_host = dso__build_id_equal(dso, host_build_id);
1662 1676
1663 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); 1677 /* Try a fast path for /proc/kallsyms if possible */
1664
1665 scnprintf(path, sizeof(path), "%s/%s/%s", buildid_dir,
1666 DSO__NAME_KCORE, sbuild_id);
1667
1668 /* Use /proc/kallsyms if possible */
1669 if (is_host) { 1678 if (is_host) {
1670 DIR *d;
1671 int fd;
1672
1673 /* If no cached kcore go with /proc/kallsyms */
1674 d = opendir(path);
1675 if (!d)
1676 goto proc_kallsyms;
1677 closedir(d);
1678
1679 /* 1679 /*
1680 * Do not check the build-id cache, until we know we cannot use 1680 * Do not check the build-id cache, unless we know we cannot use
1681 * /proc/kcore. 1681 * /proc/kcore or module maps don't match to /proc/kallsyms.
1682 * To check readability of /proc/kcore, do not use access(R_OK)
1683 * since /proc/kcore requires CAP_SYS_RAWIO to read and access
1684 * can't check it.
1682 */ 1685 */
1683 fd = open("/proc/kcore", O_RDONLY); 1686 if (filename__readable("/proc/kcore") &&
1684 if (fd != -1) { 1687 !validate_kcore_addresses("/proc/kallsyms", map))
1685 close(fd); 1688 goto proc_kallsyms;
1686 /* If module maps match go with /proc/kallsyms */
1687 if (!validate_kcore_addresses("/proc/kallsyms", map))
1688 goto proc_kallsyms;
1689 }
1690
1691 /* Find kallsyms in build-id cache with kcore */
1692 if (!find_matching_kcore(map, path, sizeof(path)))
1693 return strdup(path);
1694
1695 goto proc_kallsyms;
1696 } 1689 }
1697 1690
1691 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
1692
1698 /* Find kallsyms in build-id cache with kcore */ 1693 /* Find kallsyms in build-id cache with kcore */
1694 scnprintf(path, sizeof(path), "%s/%s/%s",
1695 buildid_dir, DSO__NAME_KCORE, sbuild_id);
1696
1699 if (!find_matching_kcore(map, path, sizeof(path))) 1697 if (!find_matching_kcore(map, path, sizeof(path)))
1700 return strdup(path); 1698 return strdup(path);
1701 1699
1702 scnprintf(path, sizeof(path), "%s/%s/%s", 1700 /* Use current /proc/kallsyms if possible */
1703 buildid_dir, DSO__NAME_KALLSYMS, sbuild_id); 1701 if (is_host) {
1702proc_kallsyms:
1703 return strdup("/proc/kallsyms");
1704 }
1704 1705
1705 if (access(path, F_OK)) { 1706 /* Finally, find a cache of kallsyms */
1707 if (!build_id_cache__kallsyms_path(sbuild_id, path, sizeof(path))) {
1706 pr_err("No kallsyms or vmlinux with build-id %s was found\n", 1708 pr_err("No kallsyms or vmlinux with build-id %s was found\n",
1707 sbuild_id); 1709 sbuild_id);
1708 return NULL; 1710 return NULL;
1709 } 1711 }
1710 1712
1711 return strdup(path); 1713 return strdup(path);
1712
1713proc_kallsyms:
1714 return strdup("/proc/kallsyms");
1715} 1714}
1716 1715
1717static int dso__load_kernel_sym(struct dso *dso, struct map *map, 1716static int dso__load_kernel_sym(struct dso *dso, struct map *map,
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 45fcb715a36b..ada58e6070bf 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -265,3 +265,14 @@ void thread__find_cpumode_addr_location(struct thread *thread,
265 break; 265 break;
266 } 266 }
267} 267}
268
269struct thread *thread__main_thread(struct machine *machine, struct thread *thread)
270{
271 if (thread->pid_ == thread->tid)
272 return thread__get(thread);
273
274 if (thread->pid_ == -1)
275 return NULL;
276
277 return machine__find_thread(machine, thread->pid_, thread->pid_);
278}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 45fba13c800b..08fcb14cf637 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -81,6 +81,8 @@ void thread__insert_map(struct thread *thread, struct map *map);
81int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp); 81int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp);
82size_t thread__fprintf(struct thread *thread, FILE *fp); 82size_t thread__fprintf(struct thread *thread, FILE *fp);
83 83
84struct thread *thread__main_thread(struct machine *machine, struct thread *thread);
85
84void thread__find_addr_map(struct thread *thread, 86void thread__find_addr_map(struct thread *thread,
85 u8 cpumode, enum map_type type, u64 addr, 87 u8 cpumode, enum map_type type, u64 addr,
86 struct addr_location *al); 88 struct addr_location *al);