aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2016-05-16 20:16:54 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2016-05-16 22:11:54 -0400
commita29d5c9b8167dbc21a7ca8c0302e3799f9063b4e (patch)
tree66086a34dd9c788e6ae1b865a56e445361feb492 /tools
parentc85b03349640b34f3545503c8429fc43005e9a92 (diff)
perf tools: Separate accounting of contexts and real addresses in a stack trace
The perf_sample->ip_callchain->nr value includes all the entries in the ip_callchain->ip[] array, real addresses and PERF_CONTEXT_{KERNEL,USER,etc}, while what the user expects is that what is in the kernel.perf_event_max_stack sysctl or in the upcoming per event perf_event_attr.sample_max_stack knob be honoured in terms of IP addresses in the stack trace. So match the kernel support and validate chain->nr taking into account both kernel.perf_event_max_stack and kernel.perf_event_max_contexts_per_stack. Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Alexei Starovoitov <ast@kernel.org> Cc: Brendan Gregg <brendan.d.gregg@gmail.com> Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: He Kuang <hekuang@huawei.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Milian Wolff <milian.wolff@kdab.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Vince Weaver <vincent.weaver@maine.edu> Cc: Wang Nan <wangnan0@huawei.com> Cc: Zefan Li <lizefan@huawei.com> Link: http://lkml.kernel.org/n/tip-mgx0jpzfdq4uq4abfa40byu0@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/perf.c3
-rw-r--r--tools/perf/util/machine.c26
-rw-r--r--tools/perf/util/util.c3
-rw-r--r--tools/perf/util/util.h3
4 files changed, 24 insertions, 11 deletions
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 797000842d40..15982cee5ef3 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -549,6 +549,9 @@ int main(int argc, const char **argv)
549 if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0) 549 if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0)
550 sysctl_perf_event_max_stack = value; 550 sysctl_perf_event_max_stack = value;
551 551
552 if (sysctl__read_int("kernel/perf_event_max_contexts_per_stack", &value) == 0)
553 sysctl_perf_event_max_contexts_per_stack = value;
554
552 cmd = extract_argv0_path(argv[0]); 555 cmd = extract_argv0_path(argv[0]);
553 if (!cmd) 556 if (!cmd)
554 cmd = "perf-help"; 557 cmd = "perf-help";
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 18dd96bdde05..7ba9fadb68af 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1811,9 +1811,9 @@ static int thread__resolve_callchain_sample(struct thread *thread,
1811{ 1811{
1812 struct branch_stack *branch = sample->branch_stack; 1812 struct branch_stack *branch = sample->branch_stack;
1813 struct ip_callchain *chain = sample->callchain; 1813 struct ip_callchain *chain = sample->callchain;
1814 int chain_nr = min(max_stack, (int)chain->nr); 1814 int chain_nr = chain->nr;
1815 u8 cpumode = PERF_RECORD_MISC_USER; 1815 u8 cpumode = PERF_RECORD_MISC_USER;
1816 int i, j, err; 1816 int i, j, err, nr_entries, nr_contexts;
1817 int skip_idx = -1; 1817 int skip_idx = -1;
1818 int first_call = 0; 1818 int first_call = 0;
1819 1819
@@ -1828,7 +1828,7 @@ static int thread__resolve_callchain_sample(struct thread *thread,
1828 * Based on DWARF debug information, some architectures skip 1828 * Based on DWARF debug information, some architectures skip
1829 * a callchain entry saved by the kernel. 1829 * a callchain entry saved by the kernel.
1830 */ 1830 */
1831 if (chain->nr < sysctl_perf_event_max_stack) 1831 if (chain_nr < sysctl_perf_event_max_stack)
1832 skip_idx = arch_skip_callchain_idx(thread, chain); 1832 skip_idx = arch_skip_callchain_idx(thread, chain);
1833 1833
1834 /* 1834 /*
@@ -1889,12 +1889,8 @@ static int thread__resolve_callchain_sample(struct thread *thread,
1889 } 1889 }
1890 1890
1891check_calls: 1891check_calls:
1892 if (chain->nr > sysctl_perf_event_max_stack && (int)chain->nr > max_stack) { 1892 for (i = first_call, nr_entries = 0, nr_contexts = 0;
1893 pr_warning("corrupted callchain. skipping...\n"); 1893 i < chain_nr && nr_entries < max_stack; i++) {
1894 return 0;
1895 }
1896
1897 for (i = first_call; i < chain_nr; i++) {
1898 u64 ip; 1894 u64 ip;
1899 1895
1900 if (callchain_param.order == ORDER_CALLEE) 1896 if (callchain_param.order == ORDER_CALLEE)
@@ -1908,6 +1904,14 @@ check_calls:
1908#endif 1904#endif
1909 ip = chain->ips[j]; 1905 ip = chain->ips[j];
1910 1906
1907 if (ip >= PERF_CONTEXT_MAX) {
1908 if (++nr_contexts > sysctl_perf_event_max_contexts_per_stack)
1909 goto out_corrupted_callchain;
1910 } else {
1911 if (++nr_entries > sysctl_perf_event_max_stack)
1912 goto out_corrupted_callchain;
1913 }
1914
1911 err = add_callchain_ip(thread, cursor, parent, root_al, &cpumode, ip); 1915 err = add_callchain_ip(thread, cursor, parent, root_al, &cpumode, ip);
1912 1916
1913 if (err) 1917 if (err)
@@ -1915,6 +1919,10 @@ check_calls:
1915 } 1919 }
1916 1920
1917 return 0; 1921 return 0;
1922
1923out_corrupted_callchain:
1924 pr_warning("corrupted callchain. skipping...\n");
1925 return 0;
1918} 1926}
1919 1927
1920static int unwind_entry(struct unwind_entry *entry, void *arg) 1928static int unwind_entry(struct unwind_entry *entry, void *arg)
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index eab077ad6ca9..23504ad5d6dd 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -33,7 +33,8 @@ struct callchain_param callchain_param = {
33unsigned int page_size; 33unsigned int page_size;
34int cacheline_size; 34int cacheline_size;
35 35
36unsigned int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH; 36int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH;
37int sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK;
37 38
38bool test_attr__enabled; 39bool test_attr__enabled;
39 40
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 7651633a8dc7..1e8c3167b9fb 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -261,7 +261,8 @@ void sighandler_dump_stack(int sig);
261 261
262extern unsigned int page_size; 262extern unsigned int page_size;
263extern int cacheline_size; 263extern int cacheline_size;
264extern unsigned int sysctl_perf_event_max_stack; 264extern int sysctl_perf_event_max_stack;
265extern int sysctl_perf_event_max_contexts_per_stack;
265 266
266struct parse_tag { 267struct parse_tag {
267 char tag; 268 char tag;