diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2016-05-16 20:16:54 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2016-05-16 22:11:54 -0400 |
commit | a29d5c9b8167dbc21a7ca8c0302e3799f9063b4e (patch) | |
tree | 66086a34dd9c788e6ae1b865a56e445361feb492 /tools | |
parent | c85b03349640b34f3545503c8429fc43005e9a92 (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.c | 3 | ||||
-rw-r--r-- | tools/perf/util/machine.c | 26 | ||||
-rw-r--r-- | tools/perf/util/util.c | 3 | ||||
-rw-r--r-- | tools/perf/util/util.h | 3 |
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 | ||
1891 | check_calls: | 1891 | check_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 | |||
1923 | out_corrupted_callchain: | ||
1924 | pr_warning("corrupted callchain. skipping...\n"); | ||
1925 | return 0; | ||
1918 | } | 1926 | } |
1919 | 1927 | ||
1920 | static int unwind_entry(struct unwind_entry *entry, void *arg) | 1928 | static 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 = { | |||
33 | unsigned int page_size; | 33 | unsigned int page_size; |
34 | int cacheline_size; | 34 | int cacheline_size; |
35 | 35 | ||
36 | unsigned int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH; | 36 | int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH; |
37 | int sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK; | ||
37 | 38 | ||
38 | bool test_attr__enabled; | 39 | bool 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 | ||
262 | extern unsigned int page_size; | 262 | extern unsigned int page_size; |
263 | extern int cacheline_size; | 263 | extern int cacheline_size; |
264 | extern unsigned int sysctl_perf_event_max_stack; | 264 | extern int sysctl_perf_event_max_stack; |
265 | extern int sysctl_perf_event_max_contexts_per_stack; | ||
265 | 266 | ||
266 | struct parse_tag { | 267 | struct parse_tag { |
267 | char tag; | 268 | char tag; |