From 39f0e7a825cfc971dc9ad40b0770c22f6f4f89b8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 24 Mar 2017 14:51:28 -0300 Subject: perf trace: Check for vfs_getname.pathname length It shouldn't be zero, but if the 'perf probe' on getname_flags() (or elsewhere in the future we need to probe to catch the pathname for syscalls like 'open' being copied from userspace to the kernel) is misplaced somehow, then we will end up not allocating space and trying to copy the "" empty string to ttrace->filename.name, causing a segfault, fix it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-c4f1t6sx1nczuzop19r5si5s@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools') diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 912fedc5b42d..33c657c15d5e 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1656,6 +1656,8 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel, goto out; filename_len = strlen(filename); + if (filename_len == 0) + goto out; if (ttrace->filename.namelen < filename_len) { char *f = realloc(ttrace->filename.name, filename_len + 1); -- cgit v1.2.3 From c04dfafa6033ca2eddc56fe188017d9ae50414c9 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 24 Mar 2017 14:54:06 -0300 Subject: perf trace: Fix up error path indentation Trivial fix removing a tab in an error path. Link: http://lkml.kernel.org/n/tip-c14mk6cqaiby8gf5rpft3d9r@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 33c657c15d5e..2425605461fe 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1663,7 +1663,7 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel, char *f = realloc(ttrace->filename.name, filename_len + 1); if (f == NULL) - goto out; + goto out; ttrace->filename.namelen = filename_len; ttrace->filename.name = f; -- cgit v1.2.3 From ef65e96e0762cb98d9abeb6737c721ca840f8092 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 24 Mar 2017 15:03:19 -0300 Subject: perf trace: Fixup thread refcounting In trace__vfs_getname() and when checking if a thread is filtered in trace__process_sample() we were not dropping the reference obtained via machine__findnew_thread(), fix it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-9gc470phavxwxv5d9w7ck8ev@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 2425605461fe..60053d49539b 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1653,17 +1653,17 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel, ttrace = thread__priv(thread); if (!ttrace) - goto out; + goto out_put; filename_len = strlen(filename); if (filename_len == 0) - goto out; + goto out_put; if (ttrace->filename.namelen < filename_len) { char *f = realloc(ttrace->filename.name, filename_len + 1); if (f == NULL) - goto out; + goto out_put; ttrace->filename.namelen = filename_len; ttrace->filename.name = f; @@ -1673,12 +1673,12 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel, ttrace->filename.pending_open = true; if (!ttrace->filename.ptr) - goto out; + goto out_put; entry_str_len = strlen(ttrace->entry_str); remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */ if (remaining_space <= 0) - goto out; + goto out_put; if (filename_len > (size_t)remaining_space) { filename += filename_len - remaining_space; @@ -1692,6 +1692,8 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel, ttrace->filename.ptr = 0; ttrace->filename.entry_str_pos = 0; +out_put: + thread__put(thread); out: return 0; } @@ -1712,6 +1714,7 @@ static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evs ttrace->runtime_ms += runtime_ms; trace->runtime_ms += runtime_ms; +out_put: thread__put(thread); return 0; @@ -1722,8 +1725,7 @@ out_dump: (pid_t)perf_evsel__intval(evsel, sample, "pid"), runtime, perf_evsel__intval(evsel, sample, "vruntime")); - thread__put(thread); - return 0; + goto out_put; } static void bpf_output__printer(enum binary_printer_ops op, @@ -1922,7 +1924,7 @@ static int trace__process_sample(struct perf_tool *tool, thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); if (thread && thread__is_filtered(thread)) - return 0; + goto out; trace__set_base_time(trace, evsel, sample); @@ -1930,7 +1932,8 @@ static int trace__process_sample(struct perf_tool *tool, ++trace->nr_events; handler(trace, evsel, event, sample); } - +out: + thread__put(thread); return err; } -- cgit v1.2.3 From c3a0bbc7ad7598dec5a204868bdf8a2b1b51df14 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 24 Mar 2017 14:15:52 +0200 Subject: perf auxtrace: Fix no_size logic in addr_filter__resolve_kernel_syms() Address filtering with kernel symbols incorrectly resulted in the error "Cannot determine size of symbol" because the no_size logic was the wrong way around. Signed-off-by: Adrian Hunter Tested-by: Andi Kleen Cc: stable@vger.kernel.org # v4.9+ Link: http://lkml.kernel.org/r/1490357752-27942-1-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/auxtrace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index c5a6e0b12452..78bd632f144d 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -1826,7 +1826,7 @@ static int addr_filter__resolve_kernel_syms(struct addr_filter *filt) filt->addr = start; if (filt->range && !filt->size && !filt->sym_to) { filt->size = size; - no_size = !!size; + no_size = !size; } } @@ -1840,7 +1840,7 @@ static int addr_filter__resolve_kernel_syms(struct addr_filter *filt) if (err) return err; filt->size = start + size - filt->addr; - no_size = !!size; + no_size = !size; } /* The very last symbol in kallsyms does not imply a particular size */ -- cgit v1.2.3 From 6963d3c387ec123753788838785e68928cb87c1b Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Mon, 27 Mar 2017 08:25:38 +0530 Subject: perf list sdt: Show option in man page Commit 40218daea1db ("perf list: Show SDT and pre-cached events") added sdt support in perf list, but it missed to update documentation. Show sdt option in man perf-list. Signed-off-by: Ravi Bangoria Acked-by: Masami Hiramatsu Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Sukadev Bhattiprolu Link: http://lkml.kernel.org/r/20170327025538.1753-1-ravi.bangoria@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-list.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index 143d98df2df9..f709de54707b 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt @@ -8,7 +8,7 @@ perf-list - List all symbolic event types SYNOPSIS -------- [verse] -'perf list' [--no-desc] [--long-desc] [hw|sw|cache|tracepoint|pmu|event_glob] +'perf list' [--no-desc] [--long-desc] [hw|sw|cache|tracepoint|pmu|sdt|event_glob] DESCRIPTION ----------- @@ -244,6 +244,8 @@ To limit the list use: . 'pmu' to print the kernel supplied PMU events. +. 'sdt' to list all Statically Defined Tracepoint events. + . If none of the above is matched, it will apply the supplied glob to all events, printing the ones that match. -- cgit v1.2.3 From b0ad8ea66445d64a469df0c710947f4cdb8ef16b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 27 Mar 2017 11:47:20 -0300 Subject: perf tools: Remove unused 'prefix' from builtin functions We got it from the git sources but never used it for anything, with the place where this would be somehow used remaining: static int run_builtin(struct cmd_struct *p, int argc, const char **argv) { prefix = NULL; if (p->option & RUN_SETUP) prefix = NULL; /* setup_perf_directory(); */ Ditch it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-uw5swz05vol0qpr32c5lpvus@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/bench.h | 20 ++++++------ tools/perf/bench/futex-hash.c | 3 +- tools/perf/bench/futex-lock-pi.c | 3 +- tools/perf/bench/futex-requeue.c | 3 +- tools/perf/bench/futex-wake-parallel.c | 3 +- tools/perf/bench/futex-wake.c | 3 +- tools/perf/bench/mem-functions.c | 4 +-- tools/perf/bench/numa.c | 2 +- tools/perf/bench/sched-messaging.c | 3 +- tools/perf/bench/sched-pipe.c | 2 +- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-bench.c | 12 +++---- tools/perf/builtin-buildid-cache.c | 3 +- tools/perf/builtin-buildid-list.c | 3 +- tools/perf/builtin-c2c.c | 4 +-- tools/perf/builtin-config.c | 2 +- tools/perf/builtin-data.c | 9 +++--- tools/perf/builtin-diff.c | 2 +- tools/perf/builtin-evlist.c | 2 +- tools/perf/builtin-ftrace.c | 2 +- tools/perf/builtin-help.c | 2 +- tools/perf/builtin-inject.c | 2 +- tools/perf/builtin-kallsyms.c | 2 +- tools/perf/builtin-kmem.c | 4 +-- tools/perf/builtin-kvm.c | 16 +++++----- tools/perf/builtin-list.c | 2 +- tools/perf/builtin-lock.c | 6 ++-- tools/perf/builtin-mem.c | 6 ++-- tools/perf/builtin-probe.c | 6 ++-- tools/perf/builtin-record.c | 2 +- tools/perf/builtin-report.c | 2 +- tools/perf/builtin-sched.c | 6 ++-- tools/perf/builtin-script.c | 4 +-- tools/perf/builtin-stat.c | 2 +- tools/perf/builtin-timechart.c | 7 ++-- tools/perf/builtin-top.c | 2 +- tools/perf/builtin-trace.c | 4 +-- tools/perf/builtin-version.c | 3 +- tools/perf/builtin.h | 58 +++++++++++++++++----------------- tools/perf/perf.c | 11 ++----- tools/perf/tests/builtin-test.c | 2 +- 41 files changed, 110 insertions(+), 126 deletions(-) (limited to 'tools') diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h index 579a592990dd..842ab2781cdc 100644 --- a/tools/perf/bench/bench.h +++ b/tools/perf/bench/bench.h @@ -25,17 +25,17 @@ # endif #endif -int bench_numa(int argc, const char **argv, const char *prefix); -int bench_sched_messaging(int argc, const char **argv, const char *prefix); -int bench_sched_pipe(int argc, const char **argv, const char *prefix); -int bench_mem_memcpy(int argc, const char **argv, const char *prefix); -int bench_mem_memset(int argc, const char **argv, const char *prefix); -int bench_futex_hash(int argc, const char **argv, const char *prefix); -int bench_futex_wake(int argc, const char **argv, const char *prefix); -int bench_futex_wake_parallel(int argc, const char **argv, const char *prefix); -int bench_futex_requeue(int argc, const char **argv, const char *prefix); +int bench_numa(int argc, const char **argv); +int bench_sched_messaging(int argc, const char **argv); +int bench_sched_pipe(int argc, const char **argv); +int bench_mem_memcpy(int argc, const char **argv); +int bench_mem_memset(int argc, const char **argv); +int bench_futex_hash(int argc, const char **argv); +int bench_futex_wake(int argc, const char **argv); +int bench_futex_wake_parallel(int argc, const char **argv); +int bench_futex_requeue(int argc, const char **argv); /* pi futexes */ -int bench_futex_lock_pi(int argc, const char **argv, const char *prefix); +int bench_futex_lock_pi(int argc, const char **argv); #define BENCH_FORMAT_DEFAULT_STR "default" #define BENCH_FORMAT_DEFAULT 0 diff --git a/tools/perf/bench/futex-hash.c b/tools/perf/bench/futex-hash.c index 2499e1b0c6fb..fe16b310097f 100644 --- a/tools/perf/bench/futex-hash.c +++ b/tools/perf/bench/futex-hash.c @@ -114,8 +114,7 @@ static void print_summary(void) (int) runtime.tv_sec); } -int bench_futex_hash(int argc, const char **argv, - const char *prefix __maybe_unused) +int bench_futex_hash(int argc, const char **argv) { int ret = 0; cpu_set_t cpu; diff --git a/tools/perf/bench/futex-lock-pi.c b/tools/perf/bench/futex-lock-pi.c index a20814d94af1..73a1c44ea63c 100644 --- a/tools/perf/bench/futex-lock-pi.c +++ b/tools/perf/bench/futex-lock-pi.c @@ -140,8 +140,7 @@ static void create_threads(struct worker *w, pthread_attr_t thread_attr) } } -int bench_futex_lock_pi(int argc, const char **argv, - const char *prefix __maybe_unused) +int bench_futex_lock_pi(int argc, const char **argv) { int ret = 0; unsigned int i; diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c index 9fad1e4fcd3e..41786cbea24c 100644 --- a/tools/perf/bench/futex-requeue.c +++ b/tools/perf/bench/futex-requeue.c @@ -109,8 +109,7 @@ static void toggle_done(int sig __maybe_unused, done = true; } -int bench_futex_requeue(int argc, const char **argv, - const char *prefix __maybe_unused) +int bench_futex_requeue(int argc, const char **argv) { int ret = 0; unsigned int i, j; diff --git a/tools/perf/bench/futex-wake-parallel.c b/tools/perf/bench/futex-wake-parallel.c index 40f5fcf1d120..4ab12c8e016a 100644 --- a/tools/perf/bench/futex-wake-parallel.c +++ b/tools/perf/bench/futex-wake-parallel.c @@ -197,8 +197,7 @@ static void toggle_done(int sig __maybe_unused, done = true; } -int bench_futex_wake_parallel(int argc, const char **argv, - const char *prefix __maybe_unused) +int bench_futex_wake_parallel(int argc, const char **argv) { int ret = 0; unsigned int i, j; diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c index 789490281ae3..2fa49222ef8d 100644 --- a/tools/perf/bench/futex-wake.c +++ b/tools/perf/bench/futex-wake.c @@ -115,8 +115,7 @@ static void toggle_done(int sig __maybe_unused, done = true; } -int bench_futex_wake(int argc, const char **argv, - const char *prefix __maybe_unused) +int bench_futex_wake(int argc, const char **argv) { int ret = 0; unsigned int i, j; diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index 52504a83b5a1..d1dea33dcfcf 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -284,7 +284,7 @@ static const char * const bench_mem_memcpy_usage[] = { NULL }; -int bench_mem_memcpy(int argc, const char **argv, const char *prefix __maybe_unused) +int bench_mem_memcpy(int argc, const char **argv) { struct bench_mem_info info = { .functions = memcpy_functions, @@ -358,7 +358,7 @@ static const struct function memset_functions[] = { { .name = NULL, } }; -int bench_mem_memset(int argc, const char **argv, const char *prefix __maybe_unused) +int bench_mem_memset(int argc, const char **argv) { struct bench_mem_info info = { .functions = memset_functions, diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c index 6bd0581de298..1fe43bd5a012 100644 --- a/tools/perf/bench/numa.c +++ b/tools/perf/bench/numa.c @@ -1767,7 +1767,7 @@ static int bench_all(void) return 0; } -int bench_numa(int argc, const char **argv, const char *prefix __maybe_unused) +int bench_numa(int argc, const char **argv) { init_params(&p0, "main,", argc, argv); argc = parse_options(argc, argv, options, bench_numa_usage, 0); diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c index 6a111e775210..4f961e74535b 100644 --- a/tools/perf/bench/sched-messaging.c +++ b/tools/perf/bench/sched-messaging.c @@ -260,8 +260,7 @@ static const char * const bench_sched_message_usage[] = { NULL }; -int bench_sched_messaging(int argc, const char **argv, - const char *prefix __maybe_unused) +int bench_sched_messaging(int argc, const char **argv) { unsigned int i, total_children; struct timeval start, stop, diff; diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c index 2243f0150d76..a152737370c5 100644 --- a/tools/perf/bench/sched-pipe.c +++ b/tools/perf/bench/sched-pipe.c @@ -76,7 +76,7 @@ static void *worker_thread(void *__tdata) return NULL; } -int bench_sched_pipe(int argc, const char **argv, const char *prefix __maybe_unused) +int bench_sched_pipe(int argc, const char **argv) { struct thread_data threads[2], *td; int pipe_1[2], pipe_2[2]; diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index e54b1f9fe1ee..56a7c8d210b9 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -383,7 +383,7 @@ static const char * const annotate_usage[] = { NULL }; -int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_annotate(int argc, const char **argv) { struct perf_annotate annotate = { .tool = { diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c index a1cddc6bbf0f..445e62881254 100644 --- a/tools/perf/builtin-bench.c +++ b/tools/perf/builtin-bench.c @@ -25,7 +25,7 @@ #include #include -typedef int (*bench_fn_t)(int argc, const char **argv, const char *prefix); +typedef int (*bench_fn_t)(int argc, const char **argv); struct bench { const char *name; @@ -155,7 +155,7 @@ static int bench_str2int(const char *str) * to something meaningful: */ static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn, - int argc, const char **argv, const char *prefix) + int argc, const char **argv) { int size; char *name; @@ -171,7 +171,7 @@ static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t f prctl(PR_SET_NAME, name); argv[0] = name; - ret = fn(argc, argv, prefix); + ret = fn(argc, argv); free(name); @@ -198,7 +198,7 @@ static void run_collection(struct collection *coll) fflush(stdout); argv[1] = bench->name; - run_bench(coll->name, bench->name, bench->fn, 1, argv, NULL); + run_bench(coll->name, bench->name, bench->fn, 1, argv); printf("\n"); } } @@ -211,7 +211,7 @@ static void run_all_collections(void) run_collection(coll); } -int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_bench(int argc, const char **argv) { struct collection *coll; int ret = 0; @@ -270,7 +270,7 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused) if (bench_format == BENCH_FORMAT_DEFAULT) printf("# Running '%s/%s' benchmark:\n", coll->name, bench->name); fflush(stdout); - ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1, prefix); + ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1); goto end; } diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index 30e2b2cb2421..94b55eee0d9b 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c @@ -276,8 +276,7 @@ static int build_id_cache__update_file(const char *filename) return err; } -int cmd_buildid_cache(int argc, const char **argv, - const char *prefix __maybe_unused) +int cmd_buildid_cache(int argc, const char **argv) { struct strlist *list; struct str_node *pos; diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 5e914ee79eb3..26f4e608207f 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c @@ -87,8 +87,7 @@ out: return 0; } -int cmd_buildid_list(int argc, const char **argv, - const char *prefix __maybe_unused) +int cmd_buildid_list(int argc, const char **argv) { bool show_kernel = false; bool with_hits = false; diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 5cd6d7a047b9..70c2c773a2b8 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -2755,12 +2755,12 @@ static int perf_c2c__record(int argc, const char **argv) pr_debug("\n"); } - ret = cmd_record(i, rec_argv, NULL); + ret = cmd_record(i, rec_argv); free(rec_argv); return ret; } -int cmd_c2c(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_c2c(int argc, const char **argv) { argc = parse_options(argc, argv, c2c_options, c2c_usage, PARSE_OPT_STOP_AT_NON_OPTION); diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c index 8c0d93b7c2f0..55f04f85b049 100644 --- a/tools/perf/builtin-config.c +++ b/tools/perf/builtin-config.c @@ -154,7 +154,7 @@ static int parse_config_arg(char *arg, char **var, char **value) return 0; } -int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_config(int argc, const char **argv) { int i, ret = 0; struct perf_config_set *set; diff --git a/tools/perf/builtin-data.c b/tools/perf/builtin-data.c index 7ad6e17ac6b3..0adb5f82335a 100644 --- a/tools/perf/builtin-data.c +++ b/tools/perf/builtin-data.c @@ -6,7 +6,7 @@ #include "data-convert.h" #include "data-convert-bt.h" -typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix); +typedef int (*data_cmd_fn_t)(int argc, const char **argv); struct data_cmd { const char *name; @@ -50,8 +50,7 @@ static const char * const data_convert_usage[] = { NULL }; -static int cmd_data_convert(int argc, const char **argv, - const char *prefix __maybe_unused) +static int cmd_data_convert(int argc, const char **argv) { const char *to_ctf = NULL; struct perf_data_convert_opts opts = { @@ -98,7 +97,7 @@ static struct data_cmd data_cmds[] = { { .name = NULL, }, }; -int cmd_data(int argc, const char **argv, const char *prefix) +int cmd_data(int argc, const char **argv) { struct data_cmd *cmd; const char *cmdstr; @@ -118,7 +117,7 @@ int cmd_data(int argc, const char **argv, const char *prefix) if (strcmp(cmd->name, cmdstr)) continue; - return cmd->fn(argc, argv, prefix); + return cmd->fn(argc, argv); } pr_err("Unknown command: %s\n", cmdstr); diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 5e4803158672..cd2605d86984 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -1321,7 +1321,7 @@ static int diff__config(const char *var, const char *value, return 0; } -int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_diff(int argc, const char **argv) { int ret = hists__init(); diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index e09c4287fe87..6d210e40d611 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c @@ -46,7 +46,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details return 0; } -int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_evlist(int argc, const char **argv) { struct perf_attr_details details = { .verbose = false, }; const struct option options[] = { diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index 6087295f8827..f80fb60b00b0 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c @@ -304,7 +304,7 @@ static int perf_ftrace_config(const char *var, const char *value, void *cb) return -1; } -int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_ftrace(int argc, const char **argv) { int ret; struct perf_ftrace ftrace = { diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index aed0d844e8c2..7ae238929e95 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -418,7 +418,7 @@ static int show_html_page(const char *perf_cmd) return 0; } -int cmd_help(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_help(int argc, const char **argv) { bool show_all = false; enum help_format help_format = HELP_FORMAT_MAN; diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 8d1d13b9bab6..42dff0b1375a 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -738,7 +738,7 @@ static int __cmd_inject(struct perf_inject *inject) return ret; } -int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_inject(int argc, const char **argv) { struct perf_inject inject = { .tool = { diff --git a/tools/perf/builtin-kallsyms.c b/tools/perf/builtin-kallsyms.c index 224bfc454b4a..8ff38c4eb2c0 100644 --- a/tools/perf/builtin-kallsyms.c +++ b/tools/perf/builtin-kallsyms.c @@ -43,7 +43,7 @@ static int __cmd_kallsyms(int argc, const char **argv) return 0; } -int cmd_kallsyms(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_kallsyms(int argc, const char **argv) { const struct option options[] = { OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index d509e74bc6e8..515587825af4 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -1866,7 +1866,7 @@ static int __cmd_record(int argc, const char **argv) for (j = 1; j < (unsigned int)argc; j++, i++) rec_argv[i] = argv[j]; - return cmd_record(i, rec_argv, NULL); + return cmd_record(i, rec_argv); } static int kmem_config(const char *var, const char *value, void *cb __maybe_unused) @@ -1885,7 +1885,7 @@ static int kmem_config(const char *var, const char *value, void *cb __maybe_unus return 0; } -int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_kmem(int argc, const char **argv) { const char * const default_slab_sort = "frag,hit,bytes"; const char * const default_page_sort = "bytes,hit"; diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 18e6c38864bc..38b409173693 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -1209,7 +1209,7 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) set_option_flag(record_options, 0, "transaction", PARSE_OPT_DISABLED); record_usage = kvm_stat_record_usage; - return cmd_record(i, rec_argv, NULL); + return cmd_record(i, rec_argv); } static int @@ -1477,7 +1477,7 @@ static int kvm_cmd_stat(const char *file_name, int argc, const char **argv) #endif perf_stat: - return cmd_stat(argc, argv, NULL); + return cmd_stat(argc, argv); } #endif /* HAVE_KVM_STAT_SUPPORT */ @@ -1496,7 +1496,7 @@ static int __cmd_record(const char *file_name, int argc, const char **argv) BUG_ON(i != rec_argc); - return cmd_record(i, rec_argv, NULL); + return cmd_record(i, rec_argv); } static int __cmd_report(const char *file_name, int argc, const char **argv) @@ -1514,7 +1514,7 @@ static int __cmd_report(const char *file_name, int argc, const char **argv) BUG_ON(i != rec_argc); - return cmd_report(i, rec_argv, NULL); + return cmd_report(i, rec_argv); } static int @@ -1533,10 +1533,10 @@ __cmd_buildid_list(const char *file_name, int argc, const char **argv) BUG_ON(i != rec_argc); - return cmd_buildid_list(i, rec_argv, NULL); + return cmd_buildid_list(i, rec_argv); } -int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_kvm(int argc, const char **argv) { const char *file_name = NULL; const struct option kvm_options[] = { @@ -1591,9 +1591,9 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) else if (!strncmp(argv[0], "rep", 3)) return __cmd_report(file_name, argc, argv); else if (!strncmp(argv[0], "diff", 4)) - return cmd_diff(argc, argv, NULL); + return cmd_diff(argc, argv); else if (!strncmp(argv[0], "top", 3)) - return cmd_top(argc, argv, NULL); + return cmd_top(argc, argv); else if (!strncmp(argv[0], "buildid-list", 12)) return __cmd_buildid_list(file_name, argc, argv); #ifdef HAVE_KVM_STAT_SUPPORT diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index be9195e95c78..4bf2cb4d25aa 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -20,7 +20,7 @@ static bool desc_flag = true; static bool details_flag; -int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_list(int argc, const char **argv) { int i; bool raw_dump = false; diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index e992e7206993..b686fb6759da 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -941,12 +941,12 @@ static int __cmd_record(int argc, const char **argv) BUG_ON(i != rec_argc); - ret = cmd_record(i, rec_argv, NULL); + ret = cmd_record(i, rec_argv); free(rec_argv); return ret; } -int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_lock(int argc, const char **argv) { const struct option lock_options[] = { OPT_STRING('i', "input", &input_name, "file", "input file name"), @@ -1009,7 +1009,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) rc = __cmd_report(false); } else if (!strcmp(argv[0], "script")) { /* Aliased to 'perf script' */ - return cmd_script(argc, argv, prefix); + return cmd_script(argc, argv); } else if (!strcmp(argv[0], "info")) { if (argc) { argc = parse_options(argc, argv, diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 030a6cfdda59..643f4faac0d0 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c @@ -129,7 +129,7 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem) pr_debug("\n"); } - ret = cmd_record(i, rec_argv, NULL); + ret = cmd_record(i, rec_argv); free(rec_argv); return ret; } @@ -256,7 +256,7 @@ static int report_events(int argc, const char **argv, struct perf_mem *mem) for (j = 1; j < argc; j++, i++) rep_argv[i] = argv[j]; - ret = cmd_report(i, rep_argv, NULL); + ret = cmd_report(i, rep_argv); free(rep_argv); return ret; } @@ -330,7 +330,7 @@ error: return ret; } -int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_mem(int argc, const char **argv) { struct stat st; struct perf_mem mem = { diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 51cdc230f6ca..d7360c2bda13 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -468,7 +468,7 @@ out: static int -__cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) +__cmd_probe(int argc, const char **argv) { const char * const probe_usage[] = { "perf probe [] 'PROBEDEF' ['PROBEDEF' ...]", @@ -687,13 +687,13 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) return 0; } -int cmd_probe(int argc, const char **argv, const char *prefix) +int cmd_probe(int argc, const char **argv) { int ret; ret = init_params(); if (!ret) { - ret = __cmd_probe(argc, argv, prefix); + ret = __cmd_probe(argc, argv); cleanup_params(); } diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 04faef79a548..3191ab063852 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1667,7 +1667,7 @@ static struct option __record_options[] = { struct option *record_options = __record_options; -int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_record(int argc, const char **argv) { int err; struct record *rec = &record; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 5ab8117c3bfd..3c8885a1c452 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -681,7 +681,7 @@ const char report_callchain_help[] = "Display call graph (stack chain/backtrace) CALLCHAIN_REPORT_HELP "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT; -int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_report(int argc, const char **argv) { struct perf_session *session; struct itrace_synth_opts itrace_synth_opts = { .set = 0, }; diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index b92c4d97192c..79833e226789 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -3272,10 +3272,10 @@ static int __cmd_record(int argc, const char **argv) BUG_ON(i != rec_argc); - return cmd_record(i, rec_argv, NULL); + return cmd_record(i, rec_argv); } -int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_sched(int argc, const char **argv) { const char default_sort_order[] = "avg, max, switch, runtime"; struct perf_sched sched = { @@ -3412,7 +3412,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) * Aliased to 'perf script' for now: */ if (!strcmp(argv[0], "script")) - return cmd_script(argc, argv, prefix); + return cmd_script(argc, argv); if (!strncmp(argv[0], "rec", 3)) { return __cmd_record(argc, argv); diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index c98e16689b57..46acc8ece41f 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -2359,7 +2359,7 @@ int process_cpu_map_event(struct perf_tool *tool __maybe_unused, return set_maps(script); } -int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_script(int argc, const char **argv) { bool show_full_info = false; bool header = false; @@ -2504,7 +2504,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) { rec_script_path = get_script_path(argv[1], RECORD_SUFFIX); if (!rec_script_path) - return cmd_record(argc, argv, NULL); + return cmd_record(argc, argv); } if (argc > 1 && !strncmp(argv[0], "rep", strlen("rep"))) { diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 01b589e3c3a6..2158ea14da57 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -2478,7 +2478,7 @@ static void setup_system_wide(int forks) } } -int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_stat(int argc, const char **argv) { const char * const stat_usage[] = { "perf stat [] []", diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index fbd7c6c695b8..fafdb44b8bcb 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -1773,7 +1773,7 @@ static int timechart__io_record(int argc, const char **argv) for (i = 0; i < (unsigned int)argc; i++) *p++ = argv[i]; - return cmd_record(rec_argc, rec_argv, NULL); + return cmd_record(rec_argc, rec_argv); } @@ -1864,7 +1864,7 @@ static int timechart__record(struct timechart *tchart, int argc, const char **ar for (j = 0; j < (unsigned int)argc; j++) *p++ = argv[j]; - return cmd_record(rec_argc, rec_argv, NULL); + return cmd_record(rec_argc, rec_argv); } static int @@ -1917,8 +1917,7 @@ parse_time(const struct option *opt, const char *arg, int __maybe_unused unset) return 0; } -int cmd_timechart(int argc, const char **argv, - const char *prefix __maybe_unused) +int cmd_timechart(int argc, const char **argv) { struct timechart tchart = { .tool = { diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index ab9077915763..a0c97c70ec81 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1075,7 +1075,7 @@ parse_percent_limit(const struct option *opt, const char *arg, const char top_callchain_help[] = CALLCHAIN_RECORD_HELP CALLCHAIN_REPORT_HELP "\n\t\t\t\tDefault: fp,graph,0.5,caller,function"; -int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_top(int argc, const char **argv) { char errbuf[BUFSIZ]; struct perf_top top = { diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 60053d49539b..c88f9f215e6f 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1993,7 +1993,7 @@ static int trace__record(struct trace *trace, int argc, const char **argv) for (i = 0; i < (unsigned int)argc; i++) rec_argv[j++] = argv[i]; - return cmd_record(j, rec_argv, NULL); + return cmd_record(j, rec_argv); } static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp); @@ -2791,7 +2791,7 @@ out: return err; } -int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_trace(int argc, const char **argv) { const char *trace_usage[] = { "perf trace [] []", diff --git a/tools/perf/builtin-version.c b/tools/perf/builtin-version.c index 9b10cda6b6dc..b9a095b1db99 100644 --- a/tools/perf/builtin-version.c +++ b/tools/perf/builtin-version.c @@ -2,8 +2,7 @@ #include "builtin.h" #include "perf.h" -int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused, - const char *prefix __maybe_unused) +int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused) { printf("perf version %s\n", perf_version_string); return 0; diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h index 036e1e35b1a8..26669bf9129c 100644 --- a/tools/perf/builtin.h +++ b/tools/perf/builtin.h @@ -13,35 +13,35 @@ void prune_packed_objects(int); int read_line_with_nul(char *buf, int size, FILE *file); int check_pager_config(const char *cmd); -int cmd_annotate(int argc, const char **argv, const char *prefix); -int cmd_bench(int argc, const char **argv, const char *prefix); -int cmd_buildid_cache(int argc, const char **argv, const char *prefix); -int cmd_buildid_list(int argc, const char **argv, const char *prefix); -int cmd_config(int argc, const char **argv, const char *prefix); -int cmd_c2c(int argc, const char **argv, const char *prefix); -int cmd_diff(int argc, const char **argv, const char *prefix); -int cmd_evlist(int argc, const char **argv, const char *prefix); -int cmd_help(int argc, const char **argv, const char *prefix); -int cmd_sched(int argc, const char **argv, const char *prefix); -int cmd_kallsyms(int argc, const char **argv, const char *prefix); -int cmd_list(int argc, const char **argv, const char *prefix); -int cmd_record(int argc, const char **argv, const char *prefix); -int cmd_report(int argc, const char **argv, const char *prefix); -int cmd_stat(int argc, const char **argv, const char *prefix); -int cmd_timechart(int argc, const char **argv, const char *prefix); -int cmd_top(int argc, const char **argv, const char *prefix); -int cmd_script(int argc, const char **argv, const char *prefix); -int cmd_version(int argc, const char **argv, const char *prefix); -int cmd_probe(int argc, const char **argv, const char *prefix); -int cmd_kmem(int argc, const char **argv, const char *prefix); -int cmd_lock(int argc, const char **argv, const char *prefix); -int cmd_kvm(int argc, const char **argv, const char *prefix); -int cmd_test(int argc, const char **argv, const char *prefix); -int cmd_trace(int argc, const char **argv, const char *prefix); -int cmd_inject(int argc, const char **argv, const char *prefix); -int cmd_mem(int argc, const char **argv, const char *prefix); -int cmd_data(int argc, const char **argv, const char *prefix); -int cmd_ftrace(int argc, const char **argv, const char *prefix); +int cmd_annotate(int argc, const char **argv); +int cmd_bench(int argc, const char **argv); +int cmd_buildid_cache(int argc, const char **argv); +int cmd_buildid_list(int argc, const char **argv); +int cmd_config(int argc, const char **argv); +int cmd_c2c(int argc, const char **argv); +int cmd_diff(int argc, const char **argv); +int cmd_evlist(int argc, const char **argv); +int cmd_help(int argc, const char **argv); +int cmd_sched(int argc, const char **argv); +int cmd_kallsyms(int argc, const char **argv); +int cmd_list(int argc, const char **argv); +int cmd_record(int argc, const char **argv); +int cmd_report(int argc, const char **argv); +int cmd_stat(int argc, const char **argv); +int cmd_timechart(int argc, const char **argv); +int cmd_top(int argc, const char **argv); +int cmd_script(int argc, const char **argv); +int cmd_version(int argc, const char **argv); +int cmd_probe(int argc, const char **argv); +int cmd_kmem(int argc, const char **argv); +int cmd_lock(int argc, const char **argv); +int cmd_kvm(int argc, const char **argv); +int cmd_test(int argc, const char **argv); +int cmd_trace(int argc, const char **argv); +int cmd_inject(int argc, const char **argv); +int cmd_mem(int argc, const char **argv); +int cmd_data(int argc, const char **argv); +int cmd_ftrace(int argc, const char **argv); int find_scripts(char **scripts_array, char **scripts_path_array); #endif diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 6d5479e03e0d..4b283d18e158 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -34,7 +34,7 @@ const char *input_name; struct cmd_struct { const char *cmd; - int (*fn)(int, const char **, const char *); + int (*fn)(int, const char **); int option; }; @@ -339,13 +339,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) { int status; struct stat st; - const char *prefix; char sbuf[STRERR_BUFSIZE]; - prefix = NULL; - if (p->option & RUN_SETUP) - prefix = NULL; /* setup_perf_directory(); */ - if (use_browser == -1) use_browser = check_browser_config(p->cmd); @@ -356,7 +351,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) commit_pager_choice(); perf_env__set_cmdline(&perf_env, argc, argv); - status = p->fn(argc, argv, prefix); + status = p->fn(argc, argv); perf_config__exit(); exit_browser(status); perf_env__exit(&perf_env); @@ -566,7 +561,7 @@ int main(int argc, const char **argv) #ifdef HAVE_LIBAUDIT_SUPPORT setup_path(); argv[0] = "trace"; - return cmd_trace(argc, argv, NULL); + return cmd_trace(argc, argv); #else fprintf(stderr, "trace command not available: missing audit-libs devel package at build time.\n"); diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 86822969e8a8..e6d7876c94c2 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -464,7 +464,7 @@ static int perf_test__list(int argc, const char **argv) return 0; } -int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused) +int cmd_test(int argc, const char **argv) { const char *test_usage[] = { "perf test [] [{list |[|]}]", -- cgit v1.2.3 From 5580338d0f207921bc1fef5b668cd564adcc3419 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Sun, 26 Mar 2017 04:34:25 +0800 Subject: perf report: Refactor common code in srcline.c Introduce dso__name() and filename_split() out of existing code because these codes will be used in several places in next patch. For filename_split(), it may also solve a potential memory leak in existing code. In existing addr2line(), sep = strchr(filename, ':'); if (sep) { *sep++ = '\0'; *file = filename; *line_nr = strtoul(sep, NULL, 0); ret = 1; } out: pclose(fp); return ret; If sep is NULL, filename is not freed or returned via file. Signed-off-by: Yao Jin Tested-by: Milian Wolff Cc: Andi Kleen Cc: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1490474069-15823-2-git-send-email-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/srcline.c | 68 +++++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 23 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index b4db3f48e3b0..2953c9fecb30 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c @@ -12,6 +12,24 @@ bool srcline_full_filename; +static const char *dso__name(struct dso *dso) +{ + const char *dso_name; + + if (dso->symsrc_filename) + dso_name = dso->symsrc_filename; + else + dso_name = dso->long_name; + + if (dso_name[0] == '[') + return NULL; + + if (!strncmp(dso_name, "/tmp/perf-", 10)) + return NULL; + + return dso_name; +} + #ifdef HAVE_LIBBFD_SUPPORT /* @@ -207,6 +225,27 @@ void dso__free_a2l(struct dso *dso) #else /* HAVE_LIBBFD_SUPPORT */ +static int filename_split(char *filename, unsigned int *line_nr) +{ + char *sep; + + sep = strchr(filename, '\n'); + if (sep) + *sep = '\0'; + + if (!strcmp(filename, "??:0")) + return 0; + + sep = strchr(filename, ':'); + if (sep) { + *sep++ = '\0'; + *line_nr = strtoul(sep, NULL, 0); + return 1; + } + + return 0; +} + static int addr2line(const char *dso_name, u64 addr, char **file, unsigned int *line_nr, struct dso *dso __maybe_unused, @@ -216,7 +255,6 @@ static int addr2line(const char *dso_name, u64 addr, char cmd[PATH_MAX]; char *filename = NULL; size_t len; - char *sep; int ret = 0; scnprintf(cmd, sizeof(cmd), "addr2line -e %s %016"PRIx64, @@ -233,23 +271,14 @@ static int addr2line(const char *dso_name, u64 addr, goto out; } - sep = strchr(filename, '\n'); - if (sep) - *sep = '\0'; - - if (!strcmp(filename, "??:0")) { - pr_debug("no debugging info in %s\n", dso_name); + ret = filename_split(filename, line_nr); + if (ret != 1) { free(filename); goto out; } - sep = strchr(filename, ':'); - if (sep) { - *sep++ = '\0'; - *file = filename; - *line_nr = strtoul(sep, NULL, 0); - ret = 1; - } + *file = filename; + out: pclose(fp); return ret; @@ -278,15 +307,8 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, if (!dso->has_srcline) goto out; - if (dso->symsrc_filename) - dso_name = dso->symsrc_filename; - else - dso_name = dso->long_name; - - if (dso_name[0] == '[') - goto out; - - if (!strncmp(dso_name, "/tmp/perf-", 10)) + dso_name = dso__name(dso); + if (dso_name == NULL) goto out; if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines)) -- cgit v1.2.3 From a64489c56c307bf0955f0489158c5ecf6aa10fe2 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Sun, 26 Mar 2017 04:34:26 +0800 Subject: perf report: Find the inline stack for a given address It would be useful for perf to support a mode to query the inline stack for a given callgraph address. This would simplify finding the right code in code that does a lot of inlining. The srcline.c has contained the code which supports to translate the address to filename:line_nr. This patch just extends the function to let it support getting the inline stacks. It introduces the inline_list which will store the inline function result (filename:line_nr and funcname). If BFD lib is not supported, the result is only filename:line_nr. Signed-off-by: Yao Jin Tested-by: Milian Wolff Cc: Andi Kleen Cc: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1490474069-15823-3-git-send-email-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/srcline.c | 167 +++++++++++++++++++++++++++++++++++++-- tools/perf/util/symbol-elf.c | 5 ++ tools/perf/util/symbol-minimal.c | 7 ++ tools/perf/util/symbol.h | 2 + tools/perf/util/util.h | 16 ++++ 5 files changed, 192 insertions(+), 5 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index 2953c9fecb30..3ce28f702b36 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c @@ -7,6 +7,7 @@ #include "util/dso.h" #include "util/util.h" #include "util/debug.h" +#include "util/callchain.h" #include "symbol.h" @@ -30,6 +31,34 @@ static const char *dso__name(struct dso *dso) return dso_name; } +static int inline_list__append(char *filename, char *funcname, int line_nr, + struct inline_node *node, struct dso *dso) +{ + struct inline_list *ilist; + char *demangled; + + ilist = zalloc(sizeof(*ilist)); + if (ilist == NULL) + return -1; + + ilist->filename = filename; + ilist->line_nr = line_nr; + + if (dso != NULL) { + demangled = dso__demangle_sym(dso, 0, funcname); + if (demangled == NULL) { + ilist->funcname = funcname; + } else { + ilist->funcname = demangled; + free(funcname); + } + } + + list_add_tail(&ilist->list, &node->val); + + return 0; +} + #ifdef HAVE_LIBBFD_SUPPORT /* @@ -169,9 +198,17 @@ static void addr2line_cleanup(struct a2l_data *a2l) #define MAX_INLINE_NEST 1024 +static void inline_list__reverse(struct inline_node *node) +{ + struct inline_list *ilist, *n; + + list_for_each_entry_safe_reverse(ilist, n, &node->val, list) + list_move_tail(&ilist->list, &node->val); +} + static int addr2line(const char *dso_name, u64 addr, char **file, unsigned int *line, struct dso *dso, - bool unwind_inlines) + bool unwind_inlines, struct inline_node *node) { int ret = 0; struct a2l_data *a2l = dso->a2l; @@ -196,8 +233,21 @@ static int addr2line(const char *dso_name, u64 addr, while (bfd_find_inliner_info(a2l->abfd, &a2l->filename, &a2l->funcname, &a2l->line) && - cnt++ < MAX_INLINE_NEST) - ; + cnt++ < MAX_INLINE_NEST) { + + if (node != NULL) { + if (inline_list__append(strdup(a2l->filename), + strdup(a2l->funcname), + a2l->line, node, + dso) != 0) + return 0; + } + } + + if ((node != NULL) && + (callchain_param.order != ORDER_CALLEE)) { + inline_list__reverse(node); + } } if (a2l->found && a2l->filename) { @@ -223,6 +273,35 @@ void dso__free_a2l(struct dso *dso) dso->a2l = NULL; } +static struct inline_node *addr2inlines(const char *dso_name, u64 addr, + struct dso *dso) +{ + char *file = NULL; + unsigned int line = 0; + struct inline_node *node; + + node = zalloc(sizeof(*node)); + if (node == NULL) { + perror("not enough memory for the inline node"); + return NULL; + } + + INIT_LIST_HEAD(&node->val); + node->addr = addr; + + if (!addr2line(dso_name, addr, &file, &line, dso, TRUE, node)) + goto out_free_inline_node; + + if (list_empty(&node->val)) + goto out_free_inline_node; + + return node; + +out_free_inline_node: + inline_node__delete(node); + return NULL; +} + #else /* HAVE_LIBBFD_SUPPORT */ static int filename_split(char *filename, unsigned int *line_nr) @@ -249,7 +328,8 @@ static int filename_split(char *filename, unsigned int *line_nr) static int addr2line(const char *dso_name, u64 addr, char **file, unsigned int *line_nr, struct dso *dso __maybe_unused, - bool unwind_inlines __maybe_unused) + bool unwind_inlines __maybe_unused, + struct inline_node *node __maybe_unused) { FILE *fp; char cmd[PATH_MAX]; @@ -288,6 +368,58 @@ void dso__free_a2l(struct dso *dso __maybe_unused) { } +static struct inline_node *addr2inlines(const char *dso_name, u64 addr, + struct dso *dso __maybe_unused) +{ + FILE *fp; + char cmd[PATH_MAX]; + struct inline_node *node; + char *filename = NULL; + size_t len; + unsigned int line_nr = 0; + + scnprintf(cmd, sizeof(cmd), "addr2line -e %s -i %016"PRIx64, + dso_name, addr); + + fp = popen(cmd, "r"); + if (fp == NULL) { + pr_err("popen failed for %s\n", dso_name); + return NULL; + } + + node = zalloc(sizeof(*node)); + if (node == NULL) { + perror("not enough memory for the inline node"); + goto out; + } + + INIT_LIST_HEAD(&node->val); + node->addr = addr; + + while (getline(&filename, &len, fp) != -1) { + if (filename_split(filename, &line_nr) != 1) { + free(filename); + goto out; + } + + if (inline_list__append(filename, NULL, line_nr, node, + NULL) != 0) + goto out; + + filename = NULL; + } + +out: + pclose(fp); + + if (list_empty(&node->val)) { + inline_node__delete(node); + return NULL; + } + + return node; +} + #endif /* HAVE_LIBBFD_SUPPORT */ /* @@ -311,7 +443,7 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, if (dso_name == NULL) goto out; - if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines)) + if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines, NULL)) goto out; if (asprintf(&srcline, "%s:%u", @@ -351,3 +483,28 @@ char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, { return __get_srcline(dso, addr, sym, show_sym, false); } + +struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr) +{ + const char *dso_name; + + dso_name = dso__name(dso); + if (dso_name == NULL) + return NULL; + + return addr2inlines(dso_name, addr, dso); +} + +void inline_node__delete(struct inline_node *node) +{ + struct inline_list *ilist, *tmp; + + list_for_each_entry_safe(ilist, tmp, &node->val, list) { + list_del_init(&ilist->list); + zfree(&ilist->filename); + zfree(&ilist->funcname); + free(ilist); + } + + free(node); +} diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 0e660dba58ad..d1a40bb642ff 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -390,6 +390,11 @@ out_elf_end: return 0; } +char *dso__demangle_sym(struct dso *dso, int kmodule, char *elf_name) +{ + return demangle_sym(dso, kmodule, elf_name); +} + /* * Align offset to 4 bytes as needed for note name and descriptor data. */ diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index 11cdde980545..870ef0f0659c 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c @@ -373,3 +373,10 @@ int kcore_copy(const char *from_dir __maybe_unused, void symbol__elf_init(void) { } + +char *dso__demangle_sym(struct dso *dso __maybe_unused, + int kmodule __maybe_unused, + char *elf_name __maybe_unused) +{ + return NULL; +} diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 9222c7e702f3..e36213ccfcf7 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -305,6 +305,8 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *map); +char *dso__demangle_sym(struct dso *dso, int kmodule, char *elf_name); + void __symbols__insert(struct rb_root *symbols, struct symbol *sym, bool kernel); void symbols__insert(struct rb_root *symbols, struct symbol *sym); void symbols__fixup_duplicate(struct rb_root *symbols); diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index b2cfa47990dc..cc0700d6fef0 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -364,4 +364,20 @@ int is_printable_array(char *p, unsigned int len); int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz); int unit_number__scnprintf(char *buf, size_t size, u64 n); + +struct inline_list { + char *filename; + char *funcname; + unsigned int line_nr; + struct list_head list; +}; + +struct inline_node { + u64 addr; + struct list_head val; +}; + +struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr); +void inline_node__delete(struct inline_node *node); + #endif /* GIT_COMPAT_UTIL_H */ -- cgit v1.2.3 From f3a60646cc3e0524d8f1083db1da7532a1590b40 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Sun, 26 Mar 2017 04:34:27 +0800 Subject: perf report: Introduce --inline option It takes some time to look for inline stack for callgraph addresses. So it provides new option "--inline" to let user decide if enable this feature. --inline: If a callgraph address belongs to an inlined function, the inline stack will be printed. Each entry is the inline function name or file/line. Signed-off-by: Yao Jin Tested-by: Milian Wolff Cc: Andi Kleen Cc: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1490474069-15823-4-git-send-email-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-report.txt | 4 ++++ tools/perf/builtin-report.c | 2 ++ tools/perf/util/symbol.h | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index e9a61f5485eb..248bba434b53 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -430,6 +430,10 @@ include::itrace.txt[] --hierarchy:: Enable hierarchical output. +--inline:: + If a callgraph address belongs to an inlined function, the inline stack + will be printed. Each entry is function name or file/line. + include::callchain-overhead-calculation.txt[] SEE ALSO diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 3c8885a1c452..c18158b83eb1 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -845,6 +845,8 @@ int cmd_report(int argc, const char **argv) stdio__config_color, "always"), OPT_STRING(0, "time", &report.time_str, "str", "Time span of interest (start,stop)"), + OPT_BOOLEAN(0, "inline", &symbol_conf.inline_name, + "Show inline function"), OPT_END() }; struct perf_data_file file = { diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index e36213ccfcf7..5245d2fb1a0a 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -118,7 +118,8 @@ struct symbol_conf { show_ref_callgraph, hide_unresolved, raw_trace, - report_hierarchy; + report_hierarchy, + inline_name; const char *vmlinux_name, *kallsyms_name, *source_prefix, -- cgit v1.2.3 From 0db64dd060f7fd77921be8f10fa9f7a5f49a3a43 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Sun, 26 Mar 2017 04:34:28 +0800 Subject: perf report: Show inline stack for stdio mode If the address belongs to an inlined function, the source information back to the first non-inlined function will be printed. For example: 1. Show inlined function name perf report --stdio -g function --inline 0.69% 0.00% inline ld-2.23.so [.] dl_main | ---dl_main | --0.56%--_dl_relocate_object _dl_relocate_object (inline) elf_dynamic_do_Rela (inline) 2. Show the file/line information perf report --stdio -g address --inline 0.69% 0.00% inline ld-2.23.so [.] _dl_start_user | ---_dl_start_user .:0 _dl_start rtld.c:307 /build/glibc-GKVZIf/glibc-2.23/elf/rtld.c:413 (inline) _dl_sysdep_start dl-sysdep.c:250 | --0.56%--dl_main rtld.c:2076 Committer tests: # perf record --call-graph dwarf ~/bin/perf stat usleep 1 Performance counter stats for 'usleep 1': 0.443020 task-clock (msec) # 0.449 CPUs utilized 1 context-switches # 0.002 M/sec 0 cpu-migrations # 0.000 K/sec 52 page-faults # 0.117 M/sec 1,049,423 cycles # 2.369 GHz 801,456 instructions # 0.76 insn per cycle 155,609 branches # 351.246 M/sec 7,026 branch-misses # 4.52% of all branches 0.000987570 seconds time elapsed [ perf record: Woken up 2 times to write data ] [ perf record: Captured and wrote 0.553 MB perf.data (66 samples) ] # perf report --stdio --inline fs__get_mountpoint 1.73% 0.00% perf perf [.] fs__get_mountpoint | ---fs__get_mountpoint fs__get_mountpoint (inline) fs__check_mounts (inline) __statfs entry_SYSCALL_64 sys_statfs SYSC_statfs user_statfs user_path_at_empty filename_lookup path_lookupat link_path_walk inode_permission __inode_permission kernfs_iop_permission kernfs_refresh_inode security_inode_notifysecctx selinux_inode_notifysecctx selinux_inode_setsecurity security_context_to_sid security_context_to_sid_core string_to_context_struct symcmp Signed-off-by: Yao Jin Tested-by: Arnaldo Carvalho de Melo Tested-by: Milian Wolff Cc: Andi Kleen Cc: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1490474069-15823-5-git-send-email-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/stdio/hist.c | 85 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 668f4aecf2e6..6128f485a3c5 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -17,6 +17,66 @@ static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) return ret; } +static size_t inline__fprintf(struct map *map, u64 ip, int left_margin, + int depth, int depth_mask, FILE *fp) +{ + struct dso *dso; + struct inline_node *node; + struct inline_list *ilist; + int ret = 0, i; + + if (map == NULL) + return 0; + + dso = map->dso; + if (dso == NULL) + return 0; + + if (dso->kernel != DSO_TYPE_USER) + return 0; + + node = dso__parse_addr_inlines(dso, + map__rip_2objdump(map, ip)); + if (node == NULL) + return 0; + + list_for_each_entry(ilist, &node->val, list) { + if ((ilist->filename != NULL) || (ilist->funcname != NULL)) { + ret += callchain__fprintf_left_margin(fp, left_margin); + + for (i = 0; i < depth; i++) { + if (depth_mask & (1 << i)) + ret += fprintf(fp, "|"); + else + ret += fprintf(fp, " "); + ret += fprintf(fp, " "); + } + + if (callchain_param.key == CCKEY_ADDRESS) { + if (ilist->filename != NULL) + ret += fprintf(fp, "%s:%d (inline)", + ilist->filename, + ilist->line_nr); + else + ret += fprintf(fp, "??"); + } else if (ilist->funcname != NULL) + ret += fprintf(fp, "%s (inline)", + ilist->funcname); + else if (ilist->filename != NULL) + ret += fprintf(fp, "%s:%d (inline)", + ilist->filename, + ilist->line_nr); + else + ret += fprintf(fp, "??"); + + ret += fprintf(fp, "\n"); + } + } + + inline_node__delete(node); + return ret; +} + static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask, int left_margin) { @@ -78,6 +138,10 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node, fputs(str, fp); fputc('\n', fp); free(alloc_str); + + if (symbol_conf.inline_name) + ret += inline__fprintf(chain->ms.map, chain->ip, + left_margin, depth, depth_mask, fp); return ret; } @@ -229,6 +293,7 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root, if (!i++ && field_order == NULL && sort_order && !prefixcmp(sort_order, "sym")) continue; + if (!printed) { ret += callchain__fprintf_left_margin(fp, left_margin); ret += fprintf(fp, "|\n"); @@ -251,6 +316,13 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root, if (++entries_printed == callchain_param.print_limit) break; + + if (symbol_conf.inline_name) + ret += inline__fprintf(chain->ms.map, + chain->ip, + left_margin, + 0, 0, + fp); } root = &cnode->rb_root; } @@ -529,6 +601,8 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, bool use_callchain) { int ret; + int callchain_ret = 0; + int inline_ret = 0; struct perf_hpp hpp = { .buf = bf, .size = size, @@ -547,7 +621,16 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, ret = fprintf(fp, "%s\n", bf); if (use_callchain) - ret += hist_entry_callchain__fprintf(he, total_period, 0, fp); + callchain_ret = hist_entry_callchain__fprintf(he, total_period, + 0, fp); + + if (callchain_ret == 0 && symbol_conf.inline_name) { + inline_ret = inline__fprintf(he->ms.map, he->ip, 0, 0, 0, fp); + ret += inline_ret; + if (inline_ret > 0) + ret += fprintf(fp, "\n"); + } else + ret += callchain_ret; return ret; } -- cgit v1.2.3 From 0d3eb0b7783f1ee6d3314f101b9cbfb988020222 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Sun, 26 Mar 2017 04:34:29 +0800 Subject: perf report: Show inline stack for browser mode If the address belongs to an inlined function, the source information back to the first non-inlined function will be printed. For example: 1. Show inlined function name perf report -g function --inline - 0.69% 0.00% inline ld-2.23.so [.] dl_main - dl_main 0.56% _dl_relocate_object _dl_relocate_object (inline) elf_dynamic_do_Rela (inline) 2. Show the file/line information perf report -g address --inline - 0.69% 0.00% inline ld-2.23.so [.] _dl_start _dl_start rtld.c:307 /build/glibc-GKVZIf/glibc-2.23/elf/rtld.c:413 (inline) + _dl_sysdep_start dl-sysdep.c:250 Signed-off-by: Yao Jin Tested-by: Arnaldo Carvalho de Melo Tested-by: Milian Wolff Cc: Andi Kleen Cc: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1490474069-15823-6-git-send-email-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 180 +++++++++++++++++++++++++++++++++++++++-- tools/perf/util/hist.c | 5 ++ tools/perf/util/sort.h | 1 + 3 files changed, 178 insertions(+), 8 deletions(-) (limited to 'tools') diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 2dc82bec10c0..62ecaebf2520 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -144,9 +144,60 @@ static void callchain_list__set_folding(struct callchain_list *cl, bool unfold) cl->unfolded = unfold ? cl->has_children : false; } +static struct inline_node *inline_node__create(struct map *map, u64 ip) +{ + struct dso *dso; + struct inline_node *node; + + if (map == NULL) + return NULL; + + dso = map->dso; + if (dso == NULL) + return NULL; + + if (dso->kernel != DSO_TYPE_USER) + return NULL; + + node = dso__parse_addr_inlines(dso, + map__rip_2objdump(map, ip)); + + return node; +} + +static int inline__count_rows(struct inline_node *node) +{ + struct inline_list *ilist; + int i = 0; + + if (node == NULL) + return 0; + + list_for_each_entry(ilist, &node->val, list) { + if ((ilist->filename != NULL) || (ilist->funcname != NULL)) + i++; + } + + return i; +} + +static int callchain_list__inline_rows(struct callchain_list *chain) +{ + struct inline_node *node; + int rows; + + node = inline_node__create(chain->ms.map, chain->ip); + if (node == NULL) + return 0; + + rows = inline__count_rows(node); + inline_node__delete(node); + return rows; +} + static int callchain_node__count_rows_rb_tree(struct callchain_node *node) { - int n = 0; + int n = 0, inline_rows; struct rb_node *nd; for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { @@ -156,6 +207,13 @@ static int callchain_node__count_rows_rb_tree(struct callchain_node *node) list_for_each_entry(chain, &child->val, list) { ++n; + + if (symbol_conf.inline_name) { + inline_rows = + callchain_list__inline_rows(chain); + n += inline_rows; + } + /* We need this because we may not have children */ folded_sign = callchain_list__folded(chain); if (folded_sign == '+') @@ -207,7 +265,7 @@ static int callchain_node__count_rows(struct callchain_node *node) { struct callchain_list *chain; bool unfolded = false; - int n = 0; + int n = 0, inline_rows; if (callchain_param.mode == CHAIN_FLAT) return callchain_node__count_flat_rows(node); @@ -216,6 +274,11 @@ static int callchain_node__count_rows(struct callchain_node *node) list_for_each_entry(chain, &node->val, list) { ++n; + if (symbol_conf.inline_name) { + inline_rows = callchain_list__inline_rows(chain); + n += inline_rows; + } + unfolded = chain->unfolded; } @@ -362,6 +425,19 @@ static void hist_entry__init_have_children(struct hist_entry *he) he->init_have_children = true; } +static void hist_entry_init_inline_node(struct hist_entry *he) +{ + if (he->inline_node) + return; + + he->inline_node = inline_node__create(he->ms.map, he->ip); + + if (he->inline_node == NULL) + return; + + he->has_children = true; +} + static bool hist_browser__toggle_fold(struct hist_browser *browser) { struct hist_entry *he = browser->he_selection; @@ -393,7 +469,12 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser) if (he->unfolded) { if (he->leaf) - he->nr_rows = callchain__count_rows(&he->sorted_chain); + if (he->inline_node) + he->nr_rows = inline__count_rows( + he->inline_node); + else + he->nr_rows = callchain__count_rows( + &he->sorted_chain); else he->nr_rows = hierarchy_count_rows(browser, he, false); @@ -753,6 +834,70 @@ static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_u #define LEVEL_OFFSET_STEP 3 +static int hist_browser__show_inline(struct hist_browser *browser, + struct inline_node *node, + unsigned short row, + int offset) +{ + struct inline_list *ilist; + char buf[1024]; + int color, width, first_row; + + first_row = row; + width = browser->b.width - (LEVEL_OFFSET_STEP + 2); + list_for_each_entry(ilist, &node->val, list) { + if ((ilist->filename != NULL) || (ilist->funcname != NULL)) { + color = HE_COLORSET_NORMAL; + if (ui_browser__is_current_entry(&browser->b, row)) + color = HE_COLORSET_SELECTED; + + if (callchain_param.key == CCKEY_ADDRESS) { + if (ilist->filename != NULL) + scnprintf(buf, sizeof(buf), + "%s:%d (inline)", + ilist->filename, + ilist->line_nr); + else + scnprintf(buf, sizeof(buf), "??"); + } else if (ilist->funcname != NULL) + scnprintf(buf, sizeof(buf), "%s (inline)", + ilist->funcname); + else if (ilist->filename != NULL) + scnprintf(buf, sizeof(buf), + "%s:%d (inline)", + ilist->filename, + ilist->line_nr); + else + scnprintf(buf, sizeof(buf), "??"); + + ui_browser__set_color(&browser->b, color); + hist_browser__gotorc(browser, row, 0); + ui_browser__write_nstring(&browser->b, " ", + LEVEL_OFFSET_STEP + offset); + ui_browser__write_nstring(&browser->b, buf, width); + row++; + } + } + + return row - first_row; +} + +static size_t show_inline_list(struct hist_browser *browser, struct map *map, + u64 ip, int row, int offset) +{ + struct inline_node *node; + int ret; + + node = inline_node__create(map, ip); + if (node == NULL) + return 0; + + ret = hist_browser__show_inline(browser, node, row, offset); + + inline_node__delete(node); + return ret; +} + static int hist_browser__show_callchain_list(struct hist_browser *browser, struct callchain_node *node, struct callchain_list *chain, @@ -764,6 +909,7 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser, char bf[1024], *alloc_str; char buf[64], *alloc_str2; const char *str; + int inline_rows = 0, ret = 1; if (arg->row_offset != 0) { arg->row_offset--; @@ -801,10 +947,15 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser, } print(browser, chain, str, offset, row, arg); - free(alloc_str); free(alloc_str2); - return 1; + + if (symbol_conf.inline_name) { + inline_rows = show_inline_list(browser, chain->ms.map, + chain->ip, row + 1, offset); + } + + return ret + inline_rows; } static bool check_percent_display(struct rb_node *node, u64 parent_total) @@ -1228,6 +1379,12 @@ static int hist_browser__show_entry(struct hist_browser *browser, folded_sign = hist_entry__folded(entry); } + if (symbol_conf.inline_name && + (!entry->has_children)) { + hist_entry_init_inline_node(entry); + folded_sign = hist_entry__folded(entry); + } + if (row_offset == 0) { struct hpp_arg arg = { .b = &browser->b, @@ -1259,7 +1416,8 @@ static int hist_browser__show_entry(struct hist_browser *browser, } if (first) { - if (symbol_conf.use_callchain) { + if (symbol_conf.use_callchain || + symbol_conf.inline_name) { ui_browser__printf(&browser->b, "%c ", folded_sign); width -= 2; } @@ -1301,8 +1459,14 @@ static int hist_browser__show_entry(struct hist_browser *browser, .is_current_entry = current_entry, }; - printed += hist_browser__show_callchain(browser, entry, 1, row, - hist_browser__show_callchain_entry, &arg, + if (entry->inline_node) + printed += hist_browser__show_inline(browser, + entry->inline_node, row, 0); + else + printed += hist_browser__show_callchain(browser, + entry, 1, row, + hist_browser__show_callchain_entry, + &arg, hist_browser__check_output_full); } diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index e3b38f629504..3c4d4d00cb2c 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -1136,6 +1136,11 @@ void hist_entry__delete(struct hist_entry *he) zfree(&he->mem_info); } + if (he->inline_node) { + inline_node__delete(he->inline_node); + he->inline_node = NULL; + } + zfree(&he->stat_acc); free_srcline(he->srcline); if (he->srcfile && he->srcfile[0]) diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index baf20a399f34..e35fb186d048 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -128,6 +128,7 @@ struct hist_entry { }; char *srcline; char *srcfile; + struct inline_node *inline_node; struct symbol *parent; struct branch_info *branch_info; struct hists *hists; -- cgit v1.2.3 From 5dfa210e407d0fedf746958bff206995bd46570d Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Sat, 18 Mar 2017 22:49:28 +0100 Subject: perf report: Enable sorting by srcline as key Often it is interesting to know how costly a given source line is in total. Previously, one had to build these sums manually based on all addresses that pointed to the same source line. This patch introduces srcline as a sort key, which will do the aggregation for us. Paired with the recent addition of showing inline frames, this makes perf report much more useful for many C++ work loads. The following shows the new feature in action. First, let's show the status quo output when we sort by address. The result contains many hist entries that generate the same output: ~~~~~~~~~~~~~~~~ $ perf report --stdio --inline -g address # Children Self Command Shared Object Symbol # ........ ........ ............ ................... ......................................... # 99.89% 35.34% cpp-inlining cpp-inlining [.] main | |--64.55%--main complex:655 | /home/milian/projects/kdab/rnd/hotspot/tests/test-clients/cpp-inlining/main.cpp:39 (inline) | /usr/include/c++/6.3.1/complex:664 (inline) | | | |--60.31%--hypot +20 | | | | | |--8.52%--__hypot_finite +273 | | | | | |--7.32%--__hypot_finite +411 ... --35.34%--_start +4194346 __libc_start_main +241 | |--6.65%--main random.tcc:3326 | /home/milian/projects/kdab/rnd/hotspot/tests/test-clients/cpp-inlining/main.cpp:39 (inline) | /usr/include/c++/6.3.1/bits/random.h:1809 (inline) | /usr/include/c++/6.3.1/bits/random.h:1818 (inline) | /usr/include/c++/6.3.1/bits/random.h:185 (inline) | |--2.70%--main random.tcc:3326 | /home/milian/projects/kdab/rnd/hotspot/tests/test-clients/cpp-inlining/main.cpp:39 (inline) | /usr/include/c++/6.3.1/bits/random.h:1809 (inline) | /usr/include/c++/6.3.1/bits/random.h:1818 (inline) | /usr/include/c++/6.3.1/bits/random.h:185 (inline) | |--1.69%--main random.tcc:3326 | /home/milian/projects/kdab/rnd/hotspot/tests/test-clients/cpp-inlining/main.cpp:39 (inline) | /usr/include/c++/6.3.1/bits/random.h:1809 (inline) | /usr/include/c++/6.3.1/bits/random.h:1818 (inline) | /usr/include/c++/6.3.1/bits/random.h:185 (inline) ... ~~~~~~~~~~~~~~~~ With this patch and `-g srcline` we instead get the following output: ~~~~~~~~~~~~~~~~ $ perf report --stdio --inline -g srcline # Children Self Command Shared Object Symbol # ........ ........ ............ ................... ......................................... # 99.89% 35.34% cpp-inlining cpp-inlining [.] main | |--64.55%--main complex:655 | /home/milian/projects/kdab/rnd/hotspot/tests/test-clients/cpp-inlining/main.cpp:39 (inline) | /usr/include/c++/6.3.1/complex:664 (inline) | | | |--64.02%--hypot | | | | | --59.81%--__hypot_finite | | | --0.53%--cabs | --35.34%--_start __libc_start_main | |--12.48%--main random.tcc:3326 | /home/milian/projects/kdab/rnd/hotspot/tests/test-clients/cpp-inlining/main.cpp:39 (inline) | /usr/include/c++/6.3.1/bits/random.h:1809 (inline) | /usr/include/c++/6.3.1/bits/random.h:1818 (inline) | /usr/include/c++/6.3.1/bits/random.h:185 (inline) ... ~~~~~~~~~~~~~~~~ Signed-off-by: Milian Wolff Cc: Jiri Olsa Cc: Yao Jin Link: http://lkml.kernel.org/r/20170318214928.9047-1-milian.wolff@kdab.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-report.txt | 1 + tools/perf/ui/browsers/hists.c | 3 +- tools/perf/ui/stdio/hist.c | 3 +- tools/perf/util/annotate.c | 3 +- tools/perf/util/callchain.c | 52 +++++++++++++++++++++++++++++--- tools/perf/util/callchain.h | 3 +- tools/perf/util/map.c | 3 +- tools/perf/util/sort.c | 16 ++++++---- tools/perf/util/srcline.c | 11 +++++-- tools/perf/util/util.h | 4 +-- 10 files changed, 78 insertions(+), 21 deletions(-) (limited to 'tools') diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 248bba434b53..37a175914157 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -235,6 +235,7 @@ OPTIONS sort_key can be: - function: compare on functions (default) - address: compare on individual code addresses + - srcline: compare on source filename and line number branch can be: - branch: include last branch information in callgraph when available. diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 62ecaebf2520..da24072bb76e 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -851,7 +851,8 @@ static int hist_browser__show_inline(struct hist_browser *browser, if (ui_browser__is_current_entry(&browser->b, row)) color = HE_COLORSET_SELECTED; - if (callchain_param.key == CCKEY_ADDRESS) { + if (callchain_param.key == CCKEY_ADDRESS || + callchain_param.key == CCKEY_SRCLINE) { if (ilist->filename != NULL) scnprintf(buf, sizeof(buf), "%s:%d (inline)", diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 6128f485a3c5..d52d5f64ea89 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -52,7 +52,8 @@ static size_t inline__fprintf(struct map *map, u64 ip, int left_margin, ret += fprintf(fp, " "); } - if (callchain_param.key == CCKEY_ADDRESS) { + if (callchain_param.key == CCKEY_ADDRESS || + callchain_param.key == CCKEY_SRCLINE) { if (ilist->filename != NULL) ret += fprintf(fp, "%s:%d (inline)", ilist->filename, diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 22cd1dbe724b..3d0263e5d1db 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1674,7 +1674,8 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, goto next; offset = start + i; - src_line->path = get_srcline(map->dso, offset, NULL, false); + src_line->path = get_srcline(map->dso, offset, NULL, + false, true); insert_source_line(&tmp_root, src_line); next: diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index aba953421a03..d78776a20e80 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -80,6 +80,10 @@ static int parse_callchain_sort_key(const char *value) callchain_param.key = CCKEY_ADDRESS; return 0; } + if (!strncmp(value, "srcline", strlen(value))) { + callchain_param.key = CCKEY_SRCLINE; + return 0; + } if (!strncmp(value, "branch", strlen(value))) { callchain_param.branch_callstack = 1; return 0; @@ -510,14 +514,51 @@ enum match_result { MATCH_GT, }; +static enum match_result match_chain_srcline(struct callchain_cursor_node *node, + struct callchain_list *cnode) +{ + char *left = get_srcline(cnode->ms.map->dso, + map__rip_2objdump(cnode->ms.map, cnode->ip), + cnode->ms.sym, true, false); + char *right = get_srcline(node->map->dso, + map__rip_2objdump(node->map, node->ip), + node->sym, true, false); + enum match_result ret = MATCH_EQ; + int cmp; + + if (left && right) + cmp = strcmp(left, right); + else if (!left && right) + cmp = 1; + else if (left && !right) + cmp = -1; + else if (cnode->ip == node->ip) + cmp = 0; + else + cmp = (cnode->ip < node->ip) ? -1 : 1; + + if (cmp != 0) + ret = cmp < 0 ? MATCH_LT : MATCH_GT; + + free_srcline(left); + free_srcline(right); + return ret; +} + static enum match_result match_chain(struct callchain_cursor_node *node, struct callchain_list *cnode) { struct symbol *sym = node->sym; u64 left, right; - if (cnode->ms.sym && sym && - callchain_param.key == CCKEY_FUNCTION) { + if (callchain_param.key == CCKEY_SRCLINE) { + enum match_result match = match_chain_srcline(node, cnode); + + if (match != MATCH_ERROR) + return match; + } + + if (cnode->ms.sym && sym && callchain_param.key == CCKEY_FUNCTION) { left = cnode->ms.sym->start; right = sym->start; } else { @@ -911,15 +952,16 @@ out: char *callchain_list__sym_name(struct callchain_list *cl, char *bf, size_t bfsize, bool show_dso) { + bool show_addr = callchain_param.key == CCKEY_ADDRESS; + bool show_srcline = show_addr || callchain_param.key == CCKEY_SRCLINE; int printed; if (cl->ms.sym) { - if (callchain_param.key == CCKEY_ADDRESS && - cl->ms.map && !cl->srcline) + if (show_srcline && cl->ms.map && !cl->srcline) cl->srcline = get_srcline(cl->ms.map->dso, map__rip_2objdump(cl->ms.map, cl->ip), - cl->ms.sym, false); + cl->ms.sym, false, show_addr); if (cl->srcline) printed = scnprintf(bf, bfsize, "%s %s", cl->ms.sym->name, cl->srcline); diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 4f4b60f1558a..c56c23dbbf72 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -77,7 +77,8 @@ typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_root *, enum chain_key { CCKEY_FUNCTION, - CCKEY_ADDRESS + CCKEY_ADDRESS, + CCKEY_SRCLINE }; enum chain_value { diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 1d9ebcf9e38e..c1870ac365a3 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -405,7 +405,8 @@ int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, if (map && map->dso) { srcline = get_srcline(map->dso, - map__rip_2objdump(map, addr), NULL, true); + map__rip_2objdump(map, addr), NULL, + true, true); if (srcline != SRCLINE_UNKNOWN) ret = fprintf(fp, "%s%s", prefix, srcline); free_srcline(srcline); diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 8b0d4e39f640..73f3ec1cf2a0 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -323,7 +323,7 @@ char *hist_entry__get_srcline(struct hist_entry *he) return SRCLINE_UNKNOWN; return get_srcline(map->dso, map__rip_2objdump(map, he->ip), - he->ms.sym, true); + he->ms.sym, true, true); } static int64_t @@ -366,7 +366,8 @@ sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right) left->branch_info->srcline_from = get_srcline(map->dso, map__rip_2objdump(map, left->branch_info->from.al_addr), - left->branch_info->from.sym, true); + left->branch_info->from.sym, + true, true); } if (!right->branch_info->srcline_from) { struct map *map = right->branch_info->from.map; @@ -376,7 +377,8 @@ sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right) right->branch_info->srcline_from = get_srcline(map->dso, map__rip_2objdump(map, right->branch_info->from.al_addr), - right->branch_info->from.sym, true); + right->branch_info->from.sym, + true, true); } return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from); } @@ -407,7 +409,8 @@ sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right) left->branch_info->srcline_to = get_srcline(map->dso, map__rip_2objdump(map, left->branch_info->to.al_addr), - left->branch_info->from.sym, true); + left->branch_info->from.sym, + true, true); } if (!right->branch_info->srcline_to) { struct map *map = right->branch_info->to.map; @@ -417,7 +420,8 @@ sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right) right->branch_info->srcline_to = get_srcline(map->dso, map__rip_2objdump(map, right->branch_info->to.al_addr), - right->branch_info->to.sym, true); + right->branch_info->to.sym, + true, true); } return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to); } @@ -448,7 +452,7 @@ static char *hist_entry__get_srcfile(struct hist_entry *e) return no_srcfile; sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip), - e->ms.sym, false, true); + e->ms.sym, false, true, true); if (!strcmp(sf, SRCLINE_UNKNOWN)) return no_srcfile; p = strchr(sf, ':'); diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index 3ce28f702b36..778ccb5d99d1 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c @@ -429,7 +429,7 @@ out: #define A2L_FAIL_LIMIT 123 char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, - bool show_sym, bool unwind_inlines) + bool show_sym, bool show_addr, bool unwind_inlines) { char *file = NULL; unsigned line = 0; @@ -463,6 +463,11 @@ out: dso->has_srcline = 0; dso__free_a2l(dso); } + + if (!show_addr) + return (show_sym && sym) ? + strndup(sym->name, sym->namelen) : NULL; + if (sym) { if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "", addr - sym->start) < 0) @@ -479,9 +484,9 @@ void free_srcline(char *srcline) } char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, - bool show_sym) + bool show_sym, bool show_addr) { - return __get_srcline(dso, addr, sym, show_sym, false); + return __get_srcline(dso, addr, sym, show_sym, show_addr, false); } struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr) diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index cc0700d6fef0..7cf5752b38fd 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -287,9 +287,9 @@ struct symbol; extern bool srcline_full_filename; char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, - bool show_sym); + bool show_sym, bool show_addr); char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, - bool show_sym, bool unwind_inlines); + bool show_sym, bool show_addr, bool unwind_inlines); void free_srcline(char *srcline); int perf_event_paranoid(void); -- cgit v1.2.3 From 6ebd2547dd24daf95a21b2bc59931de8502afcc3 Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Mon, 27 Mar 2017 16:10:36 +0900 Subject: perf annotate: Fix a bug following symbolic link of a build-id file It is wrong way to read link name from a build-id file. Because a build-id file is not anymore a symbolic link but build-id directory of it is symbolic link, so fix it. For example, if build-id file name gotten from dso__build_id_filename() is as below, /root/.debug/.build-id/4f/75c7d197c951659d1c1b8b5fd49bcdf8f3f8b1/elf To correctly read link name of build-id, use the build-id dir path that is a symbolic link, instead of the above build-id file name like below. /root/.debug/.build-id/4f/75c7d197c951659d1c1b8b5fd49bcdf8f3f8b1 Signed-off-by: Taeung Song Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/r/1490598638-13947-2-git-send-email-treeze.taeung@gmail.com Fixes: 01412261d994 ("perf buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid") Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 3d0263e5d1db..6dc9148b9b84 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1307,6 +1307,7 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil { char linkname[PATH_MAX]; char *build_id_filename; + char *build_id_path = NULL; if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && !dso__is_kcore(dso)) @@ -1322,8 +1323,14 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil goto fallback; } + build_id_path = strdup(filename); + if (!build_id_path) + return -1; + + dirname(build_id_path); + if (dso__is_kcore(dso) || - readlink(filename, linkname, sizeof(linkname)) < 0 || + readlink(build_id_path, linkname, sizeof(linkname)) < 0 || strstr(linkname, DSO__NAME_KALLSYMS) || access(filename, R_OK)) { fallback: @@ -1335,6 +1342,7 @@ fallback: __symbol__join_symfs(filename, filename_size, dso->long_name); } + free(build_id_path); return 0; } -- cgit v1.2.3 From 2e933b1274dc89cd1629f6c7fd9bf952248d84c2 Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Mon, 27 Mar 2017 16:10:37 +0900 Subject: perf annotate: Fix a bug of division by zero when calculating percent Currently perf-annotate with --print-line can print -nan(0x8000000000000) because of division by zero when calculating percent. The division by zero happens when a sum of samples is zero in symbol__get_source_line(), so fix it. For example: After running 'perf record' like below, $ perf record -e "{cycles,page-faults,branch-misses}" ./a.out Before: $ perf annotate --stdio -l Sorted summary for file /home/taeung/workspace/a.out ---------------------------------------------- 32.89 -nan 7.04 a.c:38 25.14 -nan 0.00 a.c:34 16.26 -nan 56.34 a.c:31 15.88 -nan 1.41 a.c:37 5.67 -nan 0.00 a.c:39 1.13 -nan 35.21 a.c:26 0.95 -nan 0.00 a.c:44 0.57 -nan 0.00 a.c:32 Percent | Source code & Disassembly of a.out for cycles (529 samples) ----------------------------------------------------------------------------------------- : ... a.c:26 0.57 -nan 4.23 : 40081a: mov %edi,-0x24(%rbp) a.c:26 0.00 -nan 9.86 : 40081d: mov %rsi,-0x30(%rbp) ... However, if a sum of samples is zero (e.g. 'page-faults'), skip calculating percent. After: $ perf annotate --stdio -l Sorted summary for file /home/taeung/workspace/a.out ---------------------------------------------- 32.89 0.00 7.04 a.c:38 25.14 0.00 0.00 a.c:34 16.26 0.00 56.34 a.c:31 15.88 0.00 1.41 a.c:37 5.67 0.00 0.00 a.c:39 1.13 0.00 35.21 a.c:26 0.95 0.00 0.00 a.c:44 0.57 0.00 0.00 a.c:32 Percent | Source code & Disassembly of old for cycles (529 samples) ----------------------------------------------------------------------------------------- : ... a.c:26 0.57 0.00 4.23 : 40081a: mov %edi,-0x24(%rbp) a.c:26 0.00 0.00 9.86 : 40081d: mov %rsi,-0x30(%rbp) ... Signed-off-by: Taeung Song Tested-by: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/r/1490598638-13947-3-git-send-email-treeze.taeung@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 6dc9148b9b84..11af5f0d56cc 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1671,11 +1671,15 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, src_line->nr_pcnt = nr_pcnt; for (k = 0; k < nr_pcnt; k++) { + double percent = 0.0; + h = annotation__histogram(notes, evidx + k); - src_line->samples[k].percent = 100.0 * h->addr[i] / h->sum; + if (h->sum) + percent = 100.0 * h->addr[i] / h->sum; - if (src_line->samples[k].percent > percent_max) - percent_max = src_line->samples[k].percent; + if (percent > percent_max) + percent_max = percent; + src_line->samples[k].percent = percent; } if (percent_max <= 0.5) -- cgit v1.2.3 From 2ccc220238680642be87a2d010ce07f1c40edafb Mon Sep 17 00:00:00 2001 From: Tommi Rantala Date: Wed, 22 Mar 2017 15:06:19 +0200 Subject: perf buildid: Do not update SDT cache with null filename Valgrind was complaining: ==2633== Syscall param open(filename) points to unaddressable byte(s) ==2633== at 0x5281CC0: __open_nocancel (syscall-template.S:84) ==2633== by 0x537D38: open (fcntl2.h:53) ==2633== by 0x537D38: get_sdt_note_list (symbol-elf.c:2017) ==2633== by 0x5396FD: probe_cache__scan_sdt (probe-file.c:700) ==2633== by 0x49EA2C: build_id_cache__add_sdt_cache (build-id.c:625) ==2633== by 0x49EA2C: build_id_cache__add_s (build-id.c:697) ==2633== by 0x49EE72: build_id_cache__add_b (build-id.c:717) ==2633== by 0x49EE72: dso__cache_build_id (build-id.c:782) ==2633== by 0x49F190: __dsos__cache_build_ids (build-id.c:793) ==2633== by 0x49F190: machine__cache_build_ids (build-id.c:801) ==2633== by 0x49F190: perf_session__cache_build_ids (build-id.c:815) ==2633== by 0x4CD4F2: write_build_id (header.c:165) ==2633== by 0x4D26F7: do_write_feat (header.c:2296) ==2633== by 0x4D26F7: perf_header__adds_write (header.c:2335) ==2633== by 0x4D26F7: perf_session__write_header (header.c:2414) ==2633== by 0x43B324: __cmd_record (builtin-record.c:1154) ==2633== by 0x43B324: cmd_record (builtin-record.c:1839) ==2633== by 0x455A07: __cmd_record (builtin-kmem.c:1868) ==2633== by 0x455A07: cmd_kmem (builtin-kmem.c:1944) ==2633== by 0x497150: run_builtin (perf.c:359) ==2633== by 0x428CE0: handle_internal_command (perf.c:421) ==2633== by 0x428CE0: run_argv (perf.c:467) ==2633== by 0x428CE0: main (perf.c:614) ==2633== Address 0x0 is not stack'd, malloc'd or (recently) free'd Signed-off-by: Tommi Rantala Cc: Alexander Shishkin Cc: Peter Zijlstra Cc: Tommi Rantala Link: http://lkml.kernel.org/r/20170322130624.21881-2-tommi.t.rantala@nokia.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/build-id.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index e528c40739cc..234859f756c4 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -690,7 +690,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, err = 0; /* Update SDT cache : error is just warned */ - if (build_id_cache__add_sdt_cache(sbuild_id, realname) < 0) + if (realname && build_id_cache__add_sdt_cache(sbuild_id, realname) < 0) pr_debug4("Failed to update/scan SDT cache for %s\n", realname); out_free: -- cgit v1.2.3 From 5a2342111c68e623e27ee7ea3d0492d8dad6bda0 Mon Sep 17 00:00:00 2001 From: Tommi Rantala Date: Wed, 22 Mar 2017 15:06:20 +0200 Subject: perf buildid: Do not assume that readlink() returns a null terminated string Valgrind was complaining: $ valgrind ./perf list >/dev/null ==11643== Memcheck, a memory error detector ==11643== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==11643== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info ==11643== Command: ./perf list ==11643== ==11643== Conditional jump or move depends on uninitialised value(s) ==11643== at 0x4C30620: rindex (vg_replace_strmem.c:199) ==11643== by 0x49DAA9: build_id_cache__origname (build-id.c:198) ==11643== by 0x49E1C7: build_id_cache__valid_id (build-id.c:222) ==11643== by 0x49E1C7: build_id_cache__list_all (build-id.c:507) ==11643== by 0x4B9C8F: print_sdt_events (parse-events.c:2067) ==11643== by 0x4BB0B3: print_events (parse-events.c:2313) ==11643== by 0x439501: cmd_list (builtin-list.c:53) ==11643== by 0x497150: run_builtin (perf.c:359) ==11643== by 0x428CE0: handle_internal_command (perf.c:421) ==11643== by 0x428CE0: run_argv (perf.c:467) ==11643== by 0x428CE0: main (perf.c:614) [...] Additionally, a zero length result from readlink() is not very interesting. Signed-off-by: Tommi Rantala Cc: Alexander Shishkin Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20170322130624.21881-3-tommi.t.rantala@nokia.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/build-id.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 234859f756c4..33af67530d30 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -182,13 +182,17 @@ char *build_id_cache__origname(const char *sbuild_id) char buf[PATH_MAX]; char *ret = NULL, *p; size_t offs = 5; /* == strlen("../..") */ + ssize_t len; linkname = build_id_cache__linkname(sbuild_id, NULL, 0); if (!linkname) return NULL; - if (readlink(linkname, buf, PATH_MAX) < 0) + len = readlink(linkname, buf, sizeof(buf) - 1); + if (len <= 0) goto out; + buf[len] = '\0'; + /* The link should be "../../" */ p = strrchr(buf, '/'); /* Cut off the "/" */ if (p && (p > buf + offs)) { -- cgit v1.2.3 From 0e6ba11511aef91ba8e2528ddc681d88922d7b0b Mon Sep 17 00:00:00 2001 From: Tommi Rantala Date: Wed, 22 Mar 2017 15:06:21 +0200 Subject: perf tests: Do not assume that readlink() returns a null terminated string Ensure that the string in buf is null terminated. Signed-off-by: Tommi Rantala Cc: Alexander Shishkin Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20170322130624.21881-4-tommi.t.rantala@nokia.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/sdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/tests/sdt.c b/tools/perf/tests/sdt.c index f59d210e1baf..26e5b7a0b839 100644 --- a/tools/perf/tests/sdt.c +++ b/tools/perf/tests/sdt.c @@ -43,7 +43,7 @@ static char *get_self_path(void) { char *buf = calloc(PATH_MAX, sizeof(char)); - if (buf && readlink("/proc/self/exe", buf, PATH_MAX) < 0) { + if (buf && readlink("/proc/self/exe", buf, PATH_MAX - 1) < 0) { pr_debug("Failed to get correct path of perf\n"); free(buf); return NULL; -- cgit v1.2.3 From b7126ef78612a3d4a37aadf39125cff048cebb9b Mon Sep 17 00:00:00 2001 From: Tommi Rantala Date: Wed, 22 Mar 2017 15:06:22 +0200 Subject: perf utils: use sizeof(buf) - 1 in readlink() call Ensure that we have space for the null byte in buf. Signed-off-by: Tommi Rantala Cc: Alexander Shishkin Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20170322130624.21881-5-tommi.t.rantala@nokia.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 05714d548584..cf22962ce725 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -378,7 +378,7 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused, * actual atual path to perf binary */ sprintf(proc, "/proc/%d/exe", getpid()); - ret = readlink(proc, buf, sizeof(buf)); + ret = readlink(proc, buf, sizeof(buf) - 1); if (ret <= 0) return -1; -- cgit v1.2.3 From d4b364df5f6540e8d6a38008ce2693ba73a8508a Mon Sep 17 00:00:00 2001 From: Tommi Rantala Date: Wed, 22 Mar 2017 15:06:23 +0200 Subject: perf utils: Null terminate buf in read_ftrace_printk() Ensure that the string that we read from the data file is null terminated. Valgrind was complaining: ==31357== Invalid read of size 1 ==31357== at 0x4EC8C1: __strtok_r_1c (string2.h:200) ==31357== by 0x4EC8C1: parse_ftrace_printk (trace-event-parse.c:161) ==31357== by 0x4F82A8: read_ftrace_printk (trace-event-read.c:204) ==31357== by 0x4F82A8: trace_report (trace-event-read.c:468) ==31357== by 0x4CD552: process_tracing_data (header.c:1576) ==31357== by 0x4D3397: perf_file_section__process (header.c:2705) ==31357== by 0x4D3397: perf_header__process_sections (header.c:2488) ==31357== by 0x4D3397: perf_session__read_header (header.c:2925) ==31357== by 0x4E71E2: perf_session__open (session.c:32) ==31357== by 0x4E71E2: perf_session__new (session.c:139) ==31357== by 0x429F5D: cmd_annotate (builtin-annotate.c:472) ==31357== by 0x497150: run_builtin (perf.c:359) ==31357== by 0x428CE0: handle_internal_command (perf.c:421) ==31357== by 0x428CE0: run_argv (perf.c:467) ==31357== by 0x428CE0: main (perf.c:614) ==31357== Address 0x8ac0efb is 0 bytes after a block of size 1,963 alloc'd ==31357== at 0x4C2DB9D: malloc (vg_replace_malloc.c:299) ==31357== by 0x4F827B: read_ftrace_printk (trace-event-read.c:195) ==31357== by 0x4F827B: trace_report (trace-event-read.c:468) ==31357== by 0x4CD552: process_tracing_data (header.c:1576) ==31357== by 0x4D3397: perf_file_section__process (header.c:2705) ==31357== by 0x4D3397: perf_header__process_sections (header.c:2488) ==31357== by 0x4D3397: perf_session__read_header (header.c:2925) ==31357== by 0x4E71E2: perf_session__open (session.c:32) ==31357== by 0x4E71E2: perf_session__new (session.c:139) ==31357== by 0x429F5D: cmd_annotate (builtin-annotate.c:472) ==31357== by 0x497150: run_builtin (perf.c:359) ==31357== by 0x428CE0: handle_internal_command (perf.c:421) ==31357== by 0x428CE0: run_argv (perf.c:467) ==31357== by 0x428CE0: main (perf.c:614) Signed-off-by: Tommi Rantala Cc: Alexander Shishkin Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20170322130624.21881-6-tommi.t.rantala@nokia.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/trace-event-read.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index 27420159bf69..8a9a677f7576 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -192,7 +192,7 @@ static int read_ftrace_printk(struct pevent *pevent) if (!size) return 0; - buf = malloc(size); + buf = malloc(size + 1); if (buf == NULL) return -1; @@ -201,6 +201,8 @@ static int read_ftrace_printk(struct pevent *pevent) return -1; } + buf[size] = '\0'; + parse_ftrace_printk(pevent, buf, size); free(buf); -- cgit v1.2.3 From 55f77128e7652e537d6c226d5b56821cdb5c22de Mon Sep 17 00:00:00 2001 From: Tommi Rantala Date: Wed, 22 Mar 2017 15:06:24 +0200 Subject: perf utils: Readlink /proc/self/exe to find the perf binary Simplification: it is easier to open /proc/self/exe than /proc/$pid/exe. Signed-off-by: Tommi Rantala Cc: Alexander Shishkin Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20170322130624.21881-7-tommi.t.rantala@nokia.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index cf22962ce725..ef09f26e67da 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -370,15 +370,11 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused, struct perf_evlist *evlist __maybe_unused) { char buf[MAXPATHLEN]; - char proc[32]; u32 n; int i, ret; - /* - * actual atual path to perf binary - */ - sprintf(proc, "/proc/%d/exe", getpid()); - ret = readlink(proc, buf, sizeof(buf) - 1); + /* actual path to perf binary */ + ret = readlink("/proc/self/exe", buf, sizeof(buf) - 1); if (ret <= 0) return -1; -- cgit v1.2.3