From da88c7f78d842a6938d9adde6af87a2ce262051d Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Wed, 24 Sep 2014 13:50:46 -0700 Subject: perf stat: Fix --per-core on multi socket systems On systems with more than one socket perf stat --per-core would either segfault or stop before outputting all cores. The problem was that the output code referenced the id including the socket number in the higher bits, which is far beyond any per cpu array. Mask out the socket number before referencing cpus in abs_printout. I also renamed the variable in nsec_printout to be clear what it is, even though it doesn't reference cpus. Signed-off-by: Andi Kleen Acked-by: Stephane Eranian Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1411591846-32736-1-git-send-email-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 5fe0edb1de5d..b22c62f80078 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -732,7 +732,7 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr) } } -static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) +static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) { double msecs = avg / 1e6; const char *fmt_v, *fmt_n; @@ -741,7 +741,7 @@ static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) fmt_v = csv_output ? "%.6f%s" : "%18.6f%s"; fmt_n = csv_output ? "%s" : "%-25s"; - aggr_printout(evsel, cpu, nr); + aggr_printout(evsel, id, nr); scnprintf(name, sizeof(name), "%s%s", perf_evsel__name(evsel), csv_output ? "" : " (msec)"); @@ -947,11 +947,12 @@ static void print_ll_cache_misses(int cpu, fprintf(output, " of all LL-cache hits "); } -static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) +static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) { double total, ratio = 0.0, total2; double sc = evsel->scale; const char *fmt; + int cpu = cpu_map__id_to_cpu(id); if (csv_output) { fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s"; @@ -962,7 +963,7 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) fmt = sc != 1.0 ? "%18.2f%s" : "%18.0f%s"; } - aggr_printout(evsel, cpu, nr); + aggr_printout(evsel, id, nr); if (aggr_mode == AGGR_GLOBAL) cpu = 0; -- cgit v1.2.3 From a5c2a4c9561cbbd374231bd341936dae716df9dd Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Wed, 24 Sep 2014 14:39:54 -0700 Subject: perf tools: Fix perf record as non root with kptr_restrict == 1 Currently perf record always errors out when you run it as non-root with kptr_restrict == 1, which is often the default. Make it only warn instead and fix the kernel resolve code to not segfault later. Profiling works still fine, except kernel symbols are not resolved. Signed-off-by: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1411594794-7229-1-git-send-email-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 8 ++++++-- tools/perf/util/session.c | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index ed558191c0b3..4af6b279e34a 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -558,13 +558,17 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, struct map *map; struct kmap *kmap; int err; + union perf_event *event; + + if (machine->vmlinux_maps[0] == NULL) + return -1; + /* * We should get this from /sys/kernel/sections/.text, but till that is * available use this, and after it is use this as a fallback for older * kernels. */ - union perf_event *event = zalloc((sizeof(event->mmap) + - machine->id_hdr_size)); + event = zalloc((sizeof(event->mmap) + machine->id_hdr_size)); if (event == NULL) { pr_debug("Not enough memory synthesizing mmap event " "for kernel modules\n"); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 6d2d50dea1d8..883406f4b381 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -119,7 +119,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file, * kernel MMAP event, in perf_event__process_mmap(). */ if (perf_session__create_kernel_maps(session) < 0) - goto out_delete; + pr_warning("Cannot read kernel map\n"); } if (tool && tool->ordering_requires_timestamps && -- cgit v1.2.3 From 52e0283497ccb1e675d56c9499cc2cc5ec271094 Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Wed, 24 Sep 2014 10:33:37 +0900 Subject: perf tools: Modify error code for when perf_session__new() fails Because perf_session__new() can fail for more reasons than just ENOMEM, modify error code(ENOMEM or EINVAL) to -1. Signed-off-by: Taeung Song Acked-by: Jiri Olsa Acked-by: Namhyung Kim Cc: Jiri Olsa Cc: Namhyung Kim Link: http://lkml.kernel.org/r/1411522417-9917-1-git-send-email-treeze.taeung@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-diff.c | 2 +- tools/perf/builtin-evlist.c | 2 +- tools/perf/builtin-inject.c | 2 +- tools/perf/builtin-kmem.c | 2 +- tools/perf/builtin-kvm.c | 4 ++-- tools/perf/builtin-lock.c | 2 +- tools/perf/builtin-mem.c | 2 +- tools/perf/builtin-report.c | 2 +- tools/perf/builtin-script.c | 2 +- tools/perf/builtin-timechart.c | 2 +- tools/perf/builtin-top.c | 2 +- tools/perf/builtin-trace.c | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index d4da6929597f..be5939418425 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -340,7 +340,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) annotate.session = perf_session__new(&file, false, &annotate.tool); if (annotate.session == NULL) - return -ENOMEM; + return -1; symbol_conf.priv_size = sizeof(struct annotation); symbol_conf.try_vmlinux_path = true; diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 190d0b6b28cc..a3ce19f7aebd 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -683,7 +683,7 @@ static int __cmd_diff(void) d->session = perf_session__new(&d->file, false, &tool); if (!d->session) { pr_err("Failed to open %s\n", d->file.path); - ret = -ENOMEM; + ret = -1; goto out_delete; } diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 66e12f55c052..0f93f859b782 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c @@ -28,7 +28,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details session = perf_session__new(&file, 0, NULL); if (session == NULL) - return -ENOMEM; + return -1; evlist__for_each(session->evlist, pos) perf_evsel__fprintf(pos, details, stdout); diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 3a62b6b3c8fd..de99ca1bb942 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -460,7 +460,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) file.path = inject.input_name; inject.session = perf_session__new(&file, true, &inject.tool); if (inject.session == NULL) - return -ENOMEM; + return -1; if (symbol__init(&inject.session->header.env) < 0) return -1; diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 23762187a219..f295141025bc 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -698,7 +698,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) session = perf_session__new(&file, false, &perf_kmem); if (session == NULL) - return -ENOMEM; + return -1; symbol__init(&session->header.env); diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 1e639d6265cc..d8bf2271f4ea 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -1058,7 +1058,7 @@ static int read_events(struct perf_kvm_stat *kvm) kvm->session = perf_session__new(&file, false, &kvm->tool); if (!kvm->session) { pr_err("Initializing perf session failed\n"); - return -EINVAL; + return -1; } symbol__init(&kvm->session->header.env); @@ -1361,7 +1361,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, */ kvm->session = perf_session__new(&file, false, &kvm->tool); if (kvm->session == NULL) { - err = -ENOMEM; + err = -1; goto out; } kvm->session->evlist = kvm->evlist; diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 92790ed7af45..e7ec71589da6 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -862,7 +862,7 @@ static int __cmd_report(bool display_info) session = perf_session__new(&file, false, &eops); if (!session) { pr_err("Initializing perf session failed\n"); - return -ENOMEM; + return -1; } symbol__init(&session->header.env); diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 8b4a87fe3858..24db6ffe2957 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c @@ -124,7 +124,7 @@ static int report_raw_events(struct perf_mem *mem) &mem->tool); if (session == NULL) - return -ENOMEM; + return -1; if (mem->cpu_list) { ret = perf_session__cpu_bitmap(session, mem->cpu_list, diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 8c0b3f22412a..ac145fae0521 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -720,7 +720,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) repeat: session = perf_session__new(&file, false, &report.tool); if (session == NULL) - return -ENOMEM; + return -1; if (report.queue_size) { ordered_events__set_alloc_size(&session->ordered_events, diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 02dce9295e2c..b9b9e58a6c39 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1744,7 +1744,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) session = perf_session__new(&file, false, &script.tool); if (session == NULL) - return -ENOMEM; + return -1; if (header || header_only) { perf_session__fprintf_info(session, stdout, show_full_info); diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 48eea6cd2f5b..35b425b6293f 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -1605,7 +1605,7 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name) int ret = -EINVAL; if (session == NULL) - return -ENOMEM; + return -1; symbol__init(&session->header.env); diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 832fb527ed90..5c16ba2dcf08 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -929,7 +929,7 @@ static int __cmd_top(struct perf_top *top) top->session = perf_session__new(NULL, false, NULL); if (top->session == NULL) - return -ENOMEM; + return -1; machines__set_symbol_filter(&top->session->machines, symbol_filter); diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index fe39dc620179..c70e69ea1c5d 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -2250,7 +2250,7 @@ static int trace__replay(struct trace *trace) session = perf_session__new(&file, false, &trace->tool); if (session == NULL) - return -ENOMEM; + return -1; if (symbol__init(&session->header.env) < 0) goto out; -- cgit v1.2.3 From 1da34daf24823f19cfd56c97973334cd95635926 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Tue, 23 Sep 2014 10:55:08 -0400 Subject: perf tools: Use ACCESS_ONCE() instead of volatile cast Use ACCESS_ONCE() instead of the cast to volatile and read. This is just a style change which is reader friendly. Signed-off-by: Pranith Kumar Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1411484109-10442-1-git-send-email-bobby.prani@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 8dd41cad2d59..ffb440462008 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -126,5 +126,5 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session, extern volatile int session_done; -#define session_done() (*(volatile int *)(&session_done)) +#define session_done() ACCESS_ONCE(session_done) #endif /* __PERF_SESSION_H */ -- cgit v1.2.3 From 72f72ed21e56c386dd92118e5da3ce06752b1614 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 23 Sep 2014 10:01:40 +0900 Subject: perf hists browser: Fix callchain print bug on TUI Currently perf report -g graph option doesn't work as expected and always work as same as -g fractal. This was a bug during recent callchain print code cleanup. Before: $ perf report -g graph Children Self Command Shared Object Symbol ================================================================ - 56.19% 35.41% sleep [kernel.kallsyms] [k] page_fault - page_fault + 63.02% _dl_relocate_object + 36.98% clear_user After: Children Self Command Shared Object Symbol ================================================================ - 56.19% 35.41% sleep [kernel.kallsyms] [k] page_fault - page_fault + 35.41% _dl_relocate_object + 20.78% clear_user Reviewed-by: David Ahern Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1411434104-5307-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index d4cef68176da..8f60a970404f 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -804,9 +804,6 @@ static int hist_browser__show_entry(struct hist_browser *browser, .is_current_entry = current_entry, }; - if (symbol_conf.cumulate_callchain) - total = entry->stat_acc->period; - printed += hist_browser__show_callchain(browser, &entry->sorted_chain, 1, row, total, hist_browser__show_callchain_entry, &arg, -- cgit v1.2.3 From 72a128aa083a7f4cc4f800718aaae05d9c698e26 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 23 Sep 2014 10:01:41 +0900 Subject: perf tools: Move callchain config from record_opts to callchain_param So that all callchain config parameters can be read/written to a single place. It's a preparation to consolidate handling of all callchain options. Reviewed-by: David Ahern Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1411434104-5307-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 45 ++++++++++++++++++++------------------------- tools/perf/builtin-top.c | 4 +--- tools/perf/perf.h | 3 --- tools/perf/util/callchain.h | 5 ++++- tools/perf/util/evsel.c | 11 +++++------ 5 files changed, 30 insertions(+), 38 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 320b198b54dd..fde0df72beaa 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -652,7 +652,7 @@ static int get_stack_size(char *str, unsigned long *_size) } #endif /* HAVE_DWARF_UNWIND_SUPPORT */ -int record_parse_callchain(const char *arg, struct record_opts *opts) +int record_parse_callchain(const char *arg) { char *tok, *name, *saveptr = NULL; char *buf; @@ -672,7 +672,7 @@ int record_parse_callchain(const char *arg, struct record_opts *opts) /* Framepointer style */ if (!strncmp(name, "fp", sizeof("fp"))) { if (!strtok_r(NULL, ",", &saveptr)) { - opts->call_graph = CALLCHAIN_FP; + callchain_param.record_mode = CALLCHAIN_FP; ret = 0; } else pr_err("callchain: No more arguments " @@ -685,15 +685,15 @@ int record_parse_callchain(const char *arg, struct record_opts *opts) const unsigned long default_stack_dump_size = 8192; ret = 0; - opts->call_graph = CALLCHAIN_DWARF; - opts->stack_dump_size = default_stack_dump_size; + callchain_param.record_mode = CALLCHAIN_DWARF; + callchain_param.dump_size = default_stack_dump_size; tok = strtok_r(NULL, ",", &saveptr); if (tok) { unsigned long size = 0; ret = get_stack_size(tok, &size); - opts->stack_dump_size = size; + callchain_param.dump_size = size; } #endif /* HAVE_DWARF_UNWIND_SUPPORT */ } else { @@ -708,61 +708,56 @@ int record_parse_callchain(const char *arg, struct record_opts *opts) return ret; } -static void callchain_debug(struct record_opts *opts) +static void callchain_debug(void) { static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" }; - pr_debug("callchain: type %s\n", str[opts->call_graph]); + pr_debug("callchain: type %s\n", str[callchain_param.record_mode]); - if (opts->call_graph == CALLCHAIN_DWARF) + if (callchain_param.record_mode == CALLCHAIN_DWARF) pr_debug("callchain: stack dump size %d\n", - opts->stack_dump_size); + callchain_param.dump_size); } -int record_parse_callchain_opt(const struct option *opt, +int record_parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, int unset) { - struct record_opts *opts = opt->value; int ret; - opts->call_graph_enabled = !unset; + callchain_param.enabled = !unset; /* --no-call-graph */ if (unset) { - opts->call_graph = CALLCHAIN_NONE; + callchain_param.record_mode = CALLCHAIN_NONE; pr_debug("callchain: disabled\n"); return 0; } - ret = record_parse_callchain(arg, opts); + ret = record_parse_callchain(arg); if (!ret) - callchain_debug(opts); + callchain_debug(); return ret; } -int record_callchain_opt(const struct option *opt, +int record_callchain_opt(const struct option *opt __maybe_unused, const char *arg __maybe_unused, int unset __maybe_unused) { - struct record_opts *opts = opt->value; + callchain_param.enabled = true; - opts->call_graph_enabled = !unset; + if (callchain_param.record_mode == CALLCHAIN_NONE) + callchain_param.record_mode = CALLCHAIN_FP; - if (opts->call_graph == CALLCHAIN_NONE) - opts->call_graph = CALLCHAIN_FP; - - callchain_debug(opts); + callchain_debug(); return 0; } static int perf_record_config(const char *var, const char *value, void *cb) { - struct record *rec = cb; - if (!strcmp(var, "record.call-graph")) - return record_parse_callchain(value, &rec->opts); + return record_parse_callchain(value); return perf_default_config(var, value, cb); } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 5c16ba2dcf08..f7003fc0c5f0 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1020,10 +1020,8 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) static int perf_top_config(const char *var, const char *value, void *cb) { - struct perf_top *top = cb; - if (!strcmp(var, "top.call-graph")) - return record_parse_callchain(value, &top->record_opts); + return record_parse_callchain(value); if (!strcmp(var, "top.children")) { symbol_conf.cumulate_callchain = perf_config_bool(var, value); return 0; diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 510c65f72858..220d44e44c1b 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -41,8 +41,6 @@ void pthread__unblock_sigwinch(void); struct record_opts { struct target target; - int call_graph; - bool call_graph_enabled; bool group; bool inherit_stat; bool no_buffering; @@ -60,7 +58,6 @@ struct record_opts { u64 branch_stack; u64 default_interval; u64 user_interval; - u16 stack_dump_size; bool sample_transaction; unsigned initial_delay; }; diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index da43619d6173..819ae4f61e08 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -54,6 +54,9 @@ enum chain_key { }; struct callchain_param { + bool enabled; + enum perf_call_graph_mode record_mode; + u32 dump_size; enum chain_mode mode; u32 print_limit; double min_percent; @@ -154,7 +157,7 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor) struct option; struct hist_entry; -int record_parse_callchain(const char *arg, struct record_opts *opts); +int record_parse_callchain(const char *arg); int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); int record_callchain_opt(const struct option *opt, const char *arg, int unset); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index b38de5819323..e0868a901c4a 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -503,20 +503,19 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size) } static void -perf_evsel__config_callgraph(struct perf_evsel *evsel, - struct record_opts *opts) +perf_evsel__config_callgraph(struct perf_evsel *evsel) { bool function = perf_evsel__is_function_event(evsel); struct perf_event_attr *attr = &evsel->attr; perf_evsel__set_sample_bit(evsel, CALLCHAIN); - if (opts->call_graph == CALLCHAIN_DWARF) { + if (callchain_param.record_mode == CALLCHAIN_DWARF) { if (!function) { perf_evsel__set_sample_bit(evsel, REGS_USER); perf_evsel__set_sample_bit(evsel, STACK_USER); attr->sample_regs_user = PERF_REGS_MASK; - attr->sample_stack_user = opts->stack_dump_size; + attr->sample_stack_user = callchain_param.dump_size; attr->exclude_callchain_user = 1; } else { pr_info("Cannot use DWARF unwind for function trace event," @@ -625,8 +624,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) attr->mmap_data = track; } - if (opts->call_graph_enabled && !evsel->no_aux_samples) - perf_evsel__config_callgraph(evsel, opts); + if (callchain_param.enabled && !evsel->no_aux_samples) + perf_evsel__config_callgraph(evsel); if (target__has_cpu(&opts->target)) perf_evsel__set_sample_bit(evsel, CPU); -- cgit v1.2.3 From f7f084f4d3c29b0f9877a32fc6e2feacd47695b9 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 23 Sep 2014 10:01:42 +0900 Subject: perf callchain: Move some parser functions to callchain.c And rename record_callchain_parse() to parse_callchain_record_opt() in accordance to parse_callchain_report_opt(). Reviewed-by: David Ahern Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1411434104-5307-4-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 88 ++------------------------------------------- tools/perf/builtin-top.c | 2 +- tools/perf/util/callchain.c | 84 +++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/callchain.h | 2 +- 4 files changed, 88 insertions(+), 88 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index fde0df72beaa..0ee647bcd2ec 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -624,90 +624,6 @@ error: return ret; } -#ifdef HAVE_DWARF_UNWIND_SUPPORT -static int get_stack_size(char *str, unsigned long *_size) -{ - char *endptr; - unsigned long size; - unsigned long max_size = round_down(USHRT_MAX, sizeof(u64)); - - size = strtoul(str, &endptr, 0); - - do { - if (*endptr) - break; - - size = round_up(size, sizeof(u64)); - if (!size || size > max_size) - break; - - *_size = size; - return 0; - - } while (0); - - pr_err("callchain: Incorrect stack dump size (max %ld): %s\n", - max_size, str); - return -1; -} -#endif /* HAVE_DWARF_UNWIND_SUPPORT */ - -int record_parse_callchain(const char *arg) -{ - char *tok, *name, *saveptr = NULL; - char *buf; - int ret = -1; - - /* We need buffer that we know we can write to. */ - buf = malloc(strlen(arg) + 1); - if (!buf) - return -ENOMEM; - - strcpy(buf, arg); - - tok = strtok_r((char *)buf, ",", &saveptr); - name = tok ? : (char *)buf; - - do { - /* Framepointer style */ - if (!strncmp(name, "fp", sizeof("fp"))) { - if (!strtok_r(NULL, ",", &saveptr)) { - callchain_param.record_mode = CALLCHAIN_FP; - ret = 0; - } else - pr_err("callchain: No more arguments " - "needed for -g fp\n"); - break; - -#ifdef HAVE_DWARF_UNWIND_SUPPORT - /* Dwarf style */ - } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { - const unsigned long default_stack_dump_size = 8192; - - ret = 0; - callchain_param.record_mode = CALLCHAIN_DWARF; - callchain_param.dump_size = default_stack_dump_size; - - tok = strtok_r(NULL, ",", &saveptr); - if (tok) { - unsigned long size = 0; - - ret = get_stack_size(tok, &size); - callchain_param.dump_size = size; - } -#endif /* HAVE_DWARF_UNWIND_SUPPORT */ - } else { - pr_err("callchain: Unknown --call-graph option " - "value: %s\n", arg); - break; - } - - } while (0); - - free(buf); - return ret; -} - static void callchain_debug(void) { static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" }; @@ -734,7 +650,7 @@ int record_parse_callchain_opt(const struct option *opt __maybe_unused, return 0; } - ret = record_parse_callchain(arg); + ret = parse_callchain_record_opt(arg); if (!ret) callchain_debug(); @@ -757,7 +673,7 @@ int record_callchain_opt(const struct option *opt __maybe_unused, static int perf_record_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "record.call-graph")) - return record_parse_callchain(value); + return parse_callchain_record_opt(value); return perf_default_config(var, value, cb); } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index f7003fc0c5f0..9d647a079d02 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1021,7 +1021,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) static int perf_top_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "top.call-graph")) - return record_parse_callchain(value); + return parse_callchain_record_opt(value); if (!strcmp(var, "top.children")) { symbol_conf.cumulate_callchain = perf_config_bool(var, value); return 0; diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 08f0fbf5527c..ba7297230143 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -25,6 +25,90 @@ __thread struct callchain_cursor callchain_cursor; +#ifdef HAVE_DWARF_UNWIND_SUPPORT +static int get_stack_size(const char *str, unsigned long *_size) +{ + char *endptr; + unsigned long size; + unsigned long max_size = round_down(USHRT_MAX, sizeof(u64)); + + size = strtoul(str, &endptr, 0); + + do { + if (*endptr) + break; + + size = round_up(size, sizeof(u64)); + if (!size || size > max_size) + break; + + *_size = size; + return 0; + + } while (0); + + pr_err("callchain: Incorrect stack dump size (max %ld): %s\n", + max_size, str); + return -1; +} +#endif /* HAVE_DWARF_UNWIND_SUPPORT */ + +int parse_callchain_record_opt(const char *arg) +{ + char *tok, *name, *saveptr = NULL; + char *buf; + int ret = -1; + + /* We need buffer that we know we can write to. */ + buf = malloc(strlen(arg) + 1); + if (!buf) + return -ENOMEM; + + strcpy(buf, arg); + + tok = strtok_r((char *)buf, ",", &saveptr); + name = tok ? : (char *)buf; + + do { + /* Framepointer style */ + if (!strncmp(name, "fp", sizeof("fp"))) { + if (!strtok_r(NULL, ",", &saveptr)) { + callchain_param.record_mode = CALLCHAIN_FP; + ret = 0; + } else + pr_err("callchain: No more arguments " + "needed for -g fp\n"); + break; + +#ifdef HAVE_DWARF_UNWIND_SUPPORT + /* Dwarf style */ + } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { + const unsigned long default_stack_dump_size = 8192; + + ret = 0; + callchain_param.record_mode = CALLCHAIN_DWARF; + callchain_param.dump_size = default_stack_dump_size; + + tok = strtok_r(NULL, ",", &saveptr); + if (tok) { + unsigned long size = 0; + + ret = get_stack_size(tok, &size); + callchain_param.dump_size = size; + } +#endif /* HAVE_DWARF_UNWIND_SUPPORT */ + } else { + pr_err("callchain: Unknown --call-graph option " + "value: %s\n", arg); + break; + } + + } while (0); + + free(buf); + return ret; +} + int parse_callchain_report_opt(const char *arg) { diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 819ae4f61e08..8adfbf0bab5c 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -157,7 +157,6 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor) struct option; struct hist_entry; -int record_parse_callchain(const char *arg); int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); int record_callchain_opt(const struct option *opt, const char *arg, int unset); @@ -169,6 +168,7 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node * bool hide_unresolved); extern const char record_callchain_help[]; +int parse_callchain_record_opt(const char *arg); int parse_callchain_report_opt(const char *arg); static inline void callchain_cursor_snapshot(struct callchain_cursor *dest, -- cgit v1.2.3 From 2b9240cafe9780f77b257321b13c4c4d2c2d0dc8 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 23 Sep 2014 10:01:43 +0900 Subject: perf tools: Introduce perf_callchain_config() This patch adds support for following config options to ~/.perfconfig file. [call-graph] record-mode = dwarf dump-size = 8192 print-type = fractal order = callee threshold = 0.5 print-limit = 128 sort-key = function Reviewed-by: David Ahern Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1411434104-5307-5-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/callchain.c | 109 ++++++++++++++++++++++++++++++++++++-------- tools/perf/util/callchain.h | 1 + tools/perf/util/config.c | 3 ++ 3 files changed, 94 insertions(+), 19 deletions(-) diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index ba7297230143..c84d3f8dcb75 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -109,6 +109,49 @@ int parse_callchain_record_opt(const char *arg) return ret; } +static int parse_callchain_mode(const char *value) +{ + if (!strncmp(value, "graph", strlen(value))) { + callchain_param.mode = CHAIN_GRAPH_ABS; + return 0; + } + if (!strncmp(value, "flat", strlen(value))) { + callchain_param.mode = CHAIN_FLAT; + return 0; + } + if (!strncmp(value, "fractal", strlen(value))) { + callchain_param.mode = CHAIN_GRAPH_REL; + return 0; + } + return -1; +} + +static int parse_callchain_order(const char *value) +{ + if (!strncmp(value, "caller", strlen(value))) { + callchain_param.order = ORDER_CALLER; + return 0; + } + if (!strncmp(value, "callee", strlen(value))) { + callchain_param.order = ORDER_CALLEE; + return 0; + } + return -1; +} + +static int parse_callchain_sort_key(const char *value) +{ + if (!strncmp(value, "function", strlen(value))) { + callchain_param.key = CCKEY_FUNCTION; + return 0; + } + if (!strncmp(value, "address", strlen(value))) { + callchain_param.key = CCKEY_ADDRESS; + return 0; + } + return -1; +} + int parse_callchain_report_opt(const char *arg) { @@ -128,25 +171,12 @@ parse_callchain_report_opt(const char *arg) return 0; } - /* try to get the output mode */ - if (!strncmp(tok, "graph", strlen(tok))) - callchain_param.mode = CHAIN_GRAPH_ABS; - else if (!strncmp(tok, "flat", strlen(tok))) - callchain_param.mode = CHAIN_FLAT; - else if (!strncmp(tok, "fractal", strlen(tok))) - callchain_param.mode = CHAIN_GRAPH_REL; - /* try to get the call chain order */ - else if (!strncmp(tok, "caller", strlen(tok))) - callchain_param.order = ORDER_CALLER; - else if (!strncmp(tok, "callee", strlen(tok))) - callchain_param.order = ORDER_CALLEE; - /* try to get the sort key */ - else if (!strncmp(tok, "function", strlen(tok))) - callchain_param.key = CCKEY_FUNCTION; - else if (!strncmp(tok, "address", strlen(tok))) - callchain_param.key = CCKEY_ADDRESS; - /* try to get the min percent */ - else if (!minpcnt_set) { + if (!parse_callchain_mode(tok) || + !parse_callchain_order(tok) || + !parse_callchain_sort_key(tok)) { + /* parsing ok - move on to the next */ + } else if (!minpcnt_set) { + /* try to get the min percent */ callchain_param.min_percent = strtod(tok, &endptr); if (tok == endptr) return -1; @@ -168,6 +198,47 @@ parse_callchain_report_opt(const char *arg) return 0; } +int perf_callchain_config(const char *var, const char *value) +{ + char *endptr; + + if (prefixcmp(var, "call-graph.")) + return 0; + var += sizeof("call-graph.") - 1; + + if (!strcmp(var, "record-mode")) + return parse_callchain_record_opt(value); +#ifdef HAVE_DWARF_UNWIND_SUPPORT + if (!strcmp(var, "dump-size")) { + unsigned long size = 0; + int ret; + + ret = get_stack_size(value, &size); + callchain_param.dump_size = size; + + return ret; + } +#endif + if (!strcmp(var, "print-type")) + return parse_callchain_mode(value); + if (!strcmp(var, "order")) + return parse_callchain_order(value); + if (!strcmp(var, "sort-key")) + return parse_callchain_sort_key(value); + if (!strcmp(var, "threshold")) { + callchain_param.min_percent = strtod(value, &endptr); + if (value == endptr) + return -1; + } + if (!strcmp(var, "print-limit")) { + callchain_param.print_limit = strtod(value, &endptr); + if (value == endptr) + return -1; + } + + return 0; +} + static void rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, enum chain_mode mode) diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 8adfbf0bab5c..2a1f5a46543a 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -170,6 +170,7 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node * extern const char record_callchain_help[]; int parse_callchain_record_opt(const char *arg); int parse_callchain_report_opt(const char *arg); +int perf_callchain_config(const char *var, const char *value); static inline void callchain_cursor_snapshot(struct callchain_cursor *dest, struct callchain_cursor *src) diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 9970b8b0190b..953512ed72ba 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -396,6 +396,9 @@ int perf_default_config(const char *var, const char *value, if (!prefixcmp(var, "ui.")) return perf_ui_config(var, value); + if (!prefixcmp(var, "call-graph.")) + return perf_callchain_config(var, value); + /* Add other config variables here. */ return 0; } -- cgit v1.2.3 From 5a2e5e85989025a3bb23ea5571fdac0cc5787807 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 23 Sep 2014 10:01:44 +0900 Subject: perf tools: Convert {record,top}.call-graph option to call-graph.record-mode So that it'll be passed to perf_callchain_config(). Reviewed-by: David Ahern Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1411434104-5307-6-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 2 +- tools/perf/builtin-top.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 0ee647bcd2ec..44c6f3d55ce7 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -673,7 +673,7 @@ int record_callchain_opt(const struct option *opt __maybe_unused, static int perf_record_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "record.call-graph")) - return parse_callchain_record_opt(value); + var = "call-graph.record-mode"; /* fall-through */ return perf_default_config(var, value, cb); } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 9d647a079d02..fc3d55f832ac 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1021,7 +1021,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) static int perf_top_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "top.call-graph")) - return parse_callchain_record_opt(value); + var = "call-graph.record-mode"; /* fall-through */ if (!strcmp(var, "top.children")) { symbol_conf.cumulate_callchain = perf_config_bool(var, value); return 0; -- cgit v1.2.3 From 49757c9cc7887bc79f742eb8aacf16e464ca5f0b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 23 Sep 2014 13:56:56 +0200 Subject: perf tools: Fix line number in the config file error message If we fail to parse the config file within the callback function, the line number counter 'could be' already on the next line. This results in wrong line number report like: $ cat ~/.perfconfig [call-graph] sort-key = krava $ perf record ls Fatal: bad config file line 3 in /home/jolsa/.perfconfig Fixing this by saving the current line number for this case. Signed-off-by: Jiri Olsa Acked-by: Namhyung Kim Cc: Corey Ashford Cc: David Ahern Cc: Ingo Molnar Cc: Milian Wolff Cc: Namhyung Kim Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140923115656.GC2979@krava.brq.redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/config.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 953512ed72ba..57ff826f150b 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -222,7 +222,8 @@ static int perf_parse_file(config_fn_t fn, void *data) const unsigned char *bomptr = utf8_bom; for (;;) { - int c = get_next_char(); + int line, c = get_next_char(); + if (bomptr && *bomptr) { /* We are at the file beginning; skip UTF8-encoded BOM * if present. Sane editors won't put this in on their @@ -261,8 +262,16 @@ static int perf_parse_file(config_fn_t fn, void *data) if (!isalpha(c)) break; var[baselen] = tolower(c); - if (get_value(fn, data, var, baselen+1) < 0) + + /* + * The get_value function might or might not reach the '\n', + * so saving the current line number for error reporting. + */ + line = config_linenr; + if (get_value(fn, data, var, baselen+1) < 0) { + config_linenr = line; break; + } } die("bad config file line %d in %s", config_linenr, config_file_name); } -- cgit v1.2.3