diff options
author | Ingo Molnar <mingo@kernel.org> | 2014-09-27 11:15:48 +0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-09-27 11:15:48 +0400 |
commit | 07394b5f13a04f86b27e0ddd96a36c7d9bfe1a4f (patch) | |
tree | 684f1103022db370242cc21199ca3cd5985eaac1 | |
parent | cf8102f64c8d23f0bd4af0659bbd94d0c1d8d1c7 (diff) | |
parent | 49757c9cc7887bc79f742eb8aacf16e464ca5f0b (diff) | |
download | linux-07394b5f13a04f86b27e0ddd96a36c7d9bfe1a4f.tar.xz |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
User visible changes:
o Restore "--callchain graph" output, broken in recent cset to end
up being the same as "fractal" (Namhyung Kim)
o Allow profiling when kptr_restrict == 1 for non root users,
kernel samples will just remain unresolved (Andi Kleen)
o Allow configuring default options for callchains in config file (Namhyung Kim)
o Fix line number in the config file error message (Jiri Olsa)
o Fix --per-core on multi socket systems (Andi Kleen)
Cleanups:
o Use ACCESS_ONCE() instead of volatile cast. (Pranith Kumar)
o Modify error code for when perf_session__new() fails (Taeung Song)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/perf/builtin-annotate.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-diff.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-evlist.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-inject.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-kmem.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-kvm.c | 4 | ||||
-rw-r--r-- | tools/perf/builtin-lock.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-mem.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 119 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-script.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 9 | ||||
-rw-r--r-- | tools/perf/builtin-timechart.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 6 | ||||
-rw-r--r-- | tools/perf/builtin-trace.c | 2 | ||||
-rw-r--r-- | tools/perf/perf.h | 3 | ||||
-rw-r--r-- | tools/perf/ui/browsers/hists.c | 3 | ||||
-rw-r--r-- | tools/perf/util/callchain.c | 193 | ||||
-rw-r--r-- | tools/perf/util/callchain.h | 6 | ||||
-rw-r--r-- | tools/perf/util/config.c | 16 | ||||
-rw-r--r-- | tools/perf/util/event.c | 8 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 11 | ||||
-rw-r--r-- | tools/perf/util/session.c | 2 | ||||
-rw-r--r-- | tools/perf/util/session.h | 2 |
24 files changed, 241 insertions, 163 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-record.c b/tools/perf/builtin-record.c index 320b198b54dd..44c6f3d55ce7 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -624,145 +624,56 @@ 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, struct record_opts *opts) -{ - 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)) { - opts->call_graph = 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; - opts->call_graph = CALLCHAIN_DWARF; - opts->stack_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; - } -#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(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 = parse_callchain_record_opt(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); + var = "call-graph.record-mode"; /* fall-through */ return perf_default_config(var, value, cb); } 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-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; 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..fc3d55f832ac 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); @@ -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); + var = "call-graph.record-mode"; /* fall-through */ if (!strcmp(var, "top.children")) { symbol_conf.cumulate_callchain = perf_config_bool(var, value); return 0; 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; 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/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, diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 08f0fbf5527c..c84d3f8dcb75 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -25,6 +25,133 @@ __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; +} + +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) { @@ -44,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; @@ -84,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 da43619d6173..2a1f5a46543a 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,6 @@ 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_opt(const struct option *opt, const char *arg, int unset); int record_callchain_opt(const struct option *opt, const char *arg, int unset); @@ -166,7 +168,9 @@ 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); +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..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); } @@ -396,6 +405,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; } 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/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); 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 && 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 */ |