Unwinding optimized binaries using frame pointer gives garbage. Check callchain address and stop if it's under vm.mmap_min_addr sysctl value.
Before: $ perf report --stdio --no-children -g callee ... 1.37% perf [kernel.vmlinux] [k] smp_call_function_single | ---smp_call_function_single _perf_event_enable perf_event_for_each_child perf_ioctl do_vfs_ioctl sys_ioctl entry_SYSCALL_64_fastpath __GI___ioctl 0 0 0x1c5aa70 0x1c5b910 0x1c5aa70 0x1c5b910 0x1c5aa70 0x1c5b910 0x1c5aa70 0x1c5b910 0x1c5aa70 0x1c5b910 ... After: $ perf report --stdio --no-children -g callee ... 1.37% perf [kernel.vmlinux] [k] smp_call_function_single | ---smp_call_function_single _perf_event_enable perf_event_for_each_child perf_ioctl do_vfs_ioctl sys_ioctl entry_SYSCALL_64_fastpath __GI___ioctl $ perf report --stdio --no-children -g caller ... 1.37% perf [kernel.vmlinux] [k] smp_call_function_single | ---__GI__ioctl entry_SYSCALL_64_fastpath sys_ioctl do_vfs_ioctl perf_ioctl perf_event_for_each_child _perf_event_enable smp_call_function_single Signed-off-by: Namhyung Kim <namhy...@kernel.org> --- tools/perf/perf.c | 6 ++++++ tools/perf/util/machine.c | 13 +++++++++++++ tools/perf/util/util.c | 1 + tools/perf/util/util.h | 1 + 4 files changed, 21 insertions(+) diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 4bee53c3f796..0075a6d38e3a 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -18,6 +18,7 @@ #include "util/bpf-loader.h" #include "util/debug.h" #include <api/fs/tracing_path.h> +#include <api/fs/fs.h> #include <pthread.h> const char perf_usage_string[] = @@ -528,11 +529,16 @@ int main(int argc, const char **argv) { const char *cmd; char sbuf[STRERR_BUFSIZE]; + int min_addr; /* The page_size is placed in util object. */ page_size = sysconf(_SC_PAGE_SIZE); cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); + if (sysctl__read_int("vm/mmap_min_addr", &min_addr) < 0) + min_addr = page_size; + mmap_min_addr = min_addr; + cmd = perf_extract_argv0_path(argv[0]); if (!cmd) cmd = "perf-help"; diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 7f5071a4d9aa..0a2f35e0d737 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -1860,6 +1860,19 @@ static int thread__resolve_callchain_sample(struct thread *thread, #endif ip = chain->ips[j]; + /* + * Callchain value under mmap_min_addr means it's broken + * or the end of callchain. Stop. + */ + if (ip < mmap_min_addr) { + if (callchain_param.order == ORDER_CALLEE) + break; + + /* ignore current callchains for CALLER order */ + callchain_cursor_reset(&callchain_cursor); + continue; + } + err = add_callchain_ip(thread, parent, root_al, &cpumode, ip); if (err) diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 75759aebc7b8..8e198acd9fa6 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -30,6 +30,7 @@ struct callchain_param callchain_param = { */ unsigned int page_size; int cacheline_size; +unsigned long mmap_min_addr; bool test_attr__enabled; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index dcc659017976..506d4dbb58be 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -281,6 +281,7 @@ void sighandler_dump_stack(int sig); extern unsigned int page_size; extern int cacheline_size; +extern unsigned long mmap_min_addr; void get_term_dimensions(struct winsize *ws); void set_term_quiet_input(struct termios *old); -- 2.6.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/