diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-10-29 10:29:18 +0100 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-10-29 10:29:18 +0100 |
commit | 6fc774ef4ceca99c35dd3fb230dab618f78c8d6f (patch) | |
tree | ecb640692bb7ab6a73fa92dad82d457aa0fe3bbd | |
parent | 4341801873e23bbecee76dabb7c111e3693b900f (diff) | |
parent | 443f8c75e8d58d394b0e65b47e02e5cd8ed32b41 (diff) | |
download | linux-6fc774ef4ceca99c35dd3fb230dab618f78c8d6f.tar.bz2 |
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:
- Enable per-event perf_event_attr.inherit setting by config terms, i.e.
this becomes possible:
$ perf record -e cycles/inherit/ -e instructions/no-inherit/
This affects the default, that can be changed globally using the --no-inherit
option.
This fine grained control appeared in the eBPF patchkit, but this added
flexibility may end up being useful in other scenarios. (Wang Nan)
- Setup pager when printing usage and help, we have long lists of options,
better use the pager like we do with normal tooling output, i.e. when needed,
and including any error messages in the paged output. (Namhyung Kim)
- Search for more options when passing args to -h, e.g.: (Arnaldo Carvalho de Melo)
$ perf report -h interface
Usage: perf report [<options>]
--gtk Use the GTK2 interface
--stdio Use the stdio interface
--tui Use the TUI interface
- Fix reading separate debuginfo files based on a build-id, problem
found on a Debian system. (Dima Kogan)
- Fix endless loop when splitting kallsyms symbols per section for
handling kcore files, problem found on a s390x system. (Jiri Olsa)
Infrastructure changes:
- Prep work for the 'perf stat record' work that will allow generating
perf.data files with counting data in addition to the sampling mode
we have now (Jiri Olsa)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/perf/Documentation/perf-report.txt | 2 | ||||
-rw-r--r-- | tools/perf/builtin-evlist.c | 4 | ||||
-rw-r--r-- | tools/perf/builtin-probe.c | 20 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 11 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 4 | ||||
-rw-r--r-- | tools/perf/builtin-sched.c | 4 | ||||
-rw-r--r-- | tools/perf/builtin-script.c | 8 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 59 | ||||
-rw-r--r-- | tools/perf/util/cpumap.c | 17 | ||||
-rw-r--r-- | tools/perf/util/cpumap.h | 1 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 9 | ||||
-rw-r--r-- | tools/perf/util/evsel.h | 4 | ||||
-rw-r--r-- | tools/perf/util/parse-events.c | 14 | ||||
-rw-r--r-- | tools/perf/util/parse-events.h | 2 | ||||
-rw-r--r-- | tools/perf/util/parse-events.l | 2 | ||||
-rw-r--r-- | tools/perf/util/parse-options.c | 62 | ||||
-rw-r--r-- | tools/perf/util/parse-options.h | 5 | ||||
-rw-r--r-- | tools/perf/util/strbuf.c | 22 | ||||
-rw-r--r-- | tools/perf/util/strbuf.h | 2 | ||||
-rw-r--r-- | tools/perf/util/symbol-minimal.c | 2 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 11 |
21 files changed, 216 insertions, 49 deletions
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index ab1fd64e3627..5ce8da1e1256 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -29,7 +29,7 @@ OPTIONS --show-nr-samples:: Show the number of samples for each symbol ---showcpuutilization:: +--show-cpu-utilization:: Show sample percentage for different cpu modes. -T:: diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 695ec5a50cf2..f4d62510acbb 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c @@ -61,8 +61,8 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) usage_with_options(evlist_usage, options); if (details.event_group && (details.verbose || details.freq)) { - pr_err("--group option is not compatible with other options\n"); - usage_with_options(evlist_usage, options); + usage_with_options_msg(evlist_usage, options, + "--group option is not compatible with other options\n"); } return __cmd_evlist(input_name, &details); diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 530c3a28a58c..132afc97676c 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -528,12 +528,12 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) PARSE_OPT_STOP_AT_NON_OPTION); if (argc > 0) { if (strcmp(argv[0], "-") == 0) { - pr_warning(" Error: '-' is not supported.\n"); - usage_with_options(probe_usage, options); + usage_with_options_msg(probe_usage, options, + "'-' is not supported.\n"); } if (params.command && params.command != 'a') { - pr_warning(" Error: another command except --add is set.\n"); - usage_with_options(probe_usage, options); + usage_with_options_msg(probe_usage, options, + "another command except --add is set.\n"); } ret = parse_probe_event_argv(argc, argv); if (ret < 0) { @@ -562,8 +562,10 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) switch (params.command) { case 'l': if (params.uprobes) { - pr_warning(" Error: Don't use --list with --exec.\n"); - usage_with_options(probe_usage, options); + pr_err(" Error: Don't use --list with --exec.\n"); + parse_options_usage(probe_usage, options, "l", true); + parse_options_usage(NULL, options, "x", true); + return -EINVAL; } ret = show_perf_probe_events(params.filter); if (ret < 0) @@ -603,8 +605,10 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) case 'a': /* Ensure the last given target is used */ if (params.target && !params.target_used) { - pr_warning(" Error: -x/-m must follow the probe definitions.\n"); - usage_with_options(probe_usage, options); + pr_err(" Error: -x/-m must follow the probe definitions.\n"); + parse_options_usage(probe_usage, options, "m", true); + parse_options_usage(NULL, options, "x", true); + return -EINVAL; } ret = perf_add_probe_events(params.events, params.nevents); diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 2740d7a82ae8..de02267c73d8 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1135,14 +1135,15 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) usage_with_options(record_usage, record_options); if (nr_cgroups && !rec->opts.target.system_wide) { - ui__error("cgroup monitoring only available in" - " system-wide mode\n"); - usage_with_options(record_usage, record_options); + usage_with_options_msg(record_usage, record_options, + "cgroup monitoring only available in system-wide mode"); + } if (rec->opts.record_switch_events && !perf_can_record_switch_events()) { - ui__error("kernel does not support recording context switch events (--switch-events option)\n"); - usage_with_options(record_usage, record_options); + ui__error("kernel does not support recording context switch events\n"); + parse_options_usage(record_usage, record_options, "switch-events", 0); + return -EINVAL; } if (!rec->itr) { diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 50dd4d3d8667..2853ad2bd435 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -699,8 +699,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) " Please refer the man page for the complete list."), OPT_STRING('F', "fields", &field_order, "key[,keys...]", "output field(s): overhead, period, sample plus all of sort keys"), - OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, + OPT_BOOLEAN(0, "show-cpu-utilization", &symbol_conf.show_cpu_utilization, "Show sample percentage for different cpu modes"), + OPT_BOOLEAN_FLAG(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, + "Show sample percentage for different cpu modes", PARSE_OPT_HIDDEN), OPT_STRING('p', "parent", &parent_pattern, "regex", "regex filter to identify parent, see: '--sort parent'"), OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 33962612a5e9..0ee6d900e100 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1728,8 +1728,8 @@ static void setup_sorting(struct perf_sched *sched, const struct option *options for (tok = strtok_r(str, ", ", &tmp); tok; tok = strtok_r(NULL, ", ", &tmp)) { if (sort_dimension__add(tok, &sched->sort_list) < 0) { - error("Unknown --sort key: `%s'", tok); - usage_with_options(usage_msg, options); + usage_with_options_msg(usage_msg, options, + "Unknown --sort key: `%s'", tok); } } diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 2653c0273b89..278acb22f029 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1767,9 +1767,9 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) rep_script_path = get_script_path(argv[0], REPORT_SUFFIX); if (!rec_script_path && !rep_script_path) { - fprintf(stderr, " Couldn't find script %s\n\n See perf" + usage_with_options_msg(script_usage, options, + "Couldn't find script `%s'\n\n See perf" " script -l for available scripts.\n", argv[0]); - usage_with_options(script_usage, options); } if (is_top_script(argv[0])) { @@ -1780,10 +1780,10 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) rep_args = has_required_arg(rep_script_path); rec_args = (argc - 1) - rep_args; if (rec_args < 0) { - fprintf(stderr, " %s script requires options." + usage_with_options_msg(script_usage, options, + "`%s' script requires options." "\n\n See perf script -l for available " "scripts and options.\n", argv[0]); - usage_with_options(script_usage, options); } } diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 91e793a76929..2f438f76cceb 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -100,6 +100,8 @@ static struct target target = { .uid = UINT_MAX, }; +typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu); + static int run_count = 1; static bool no_inherit = false; static volatile pid_t child_pid = -1; @@ -119,7 +121,7 @@ static unsigned int unit_width = 4; /* strlen("unit") */ static bool forever = false; static struct timespec ref_time; static struct cpu_map *aggr_map; -static int (*aggr_get_id)(struct cpu_map *m, int cpu); +static aggr_get_id_t aggr_get_id; static volatile int done = 0; @@ -954,22 +956,63 @@ static int perf_stat__get_core(struct cpu_map *map, int cpu) return cpu_map__get_core(map, cpu, NULL); } +static int cpu_map__get_max(struct cpu_map *map) +{ + int i, max = -1; + + for (i = 0; i < map->nr; i++) { + if (map->map[i] > max) + max = map->map[i]; + } + + return max; +} + +static struct cpu_map *cpus_aggr_map; + +static int perf_stat__get_aggr(aggr_get_id_t get_id, struct cpu_map *map, int idx) +{ + int cpu; + + if (idx >= map->nr) + return -1; + + cpu = map->map[idx]; + + if (cpus_aggr_map->map[cpu] == -1) + cpus_aggr_map->map[cpu] = get_id(map, idx); + + return cpus_aggr_map->map[cpu]; +} + +static int perf_stat__get_socket_cached(struct cpu_map *map, int idx) +{ + return perf_stat__get_aggr(perf_stat__get_socket, map, idx); +} + +static int perf_stat__get_core_cached(struct cpu_map *map, int idx) +{ + return perf_stat__get_aggr(perf_stat__get_core, map, idx); +} + static int perf_stat_init_aggr_mode(void) { + int nr; + switch (stat_config.aggr_mode) { case AGGR_SOCKET: if (cpu_map__build_socket_map(evsel_list->cpus, &aggr_map)) { perror("cannot build socket map"); return -1; } - aggr_get_id = perf_stat__get_socket; + aggr_get_id = perf_stat__get_socket_cached; break; case AGGR_CORE: if (cpu_map__build_core_map(evsel_list->cpus, &aggr_map)) { perror("cannot build core map"); return -1; } - aggr_get_id = perf_stat__get_core; + aggr_get_id = perf_stat__get_core_cached; break; case AGGR_NONE: case AGGR_GLOBAL: @@ -978,7 +1021,15 @@ static int perf_stat_init_aggr_mode(void) default: break; } - return 0; + + /* + * The evsel_list->cpus is the base we operate on, + * taking the highest cpu number to be the size of + * the aggregation translate cpumap. + */ + nr = cpu_map__get_max(evsel_list->cpus); + cpus_aggr_map = cpu_map__empty_new(nr + 1); + return cpus_aggr_map ? 0 : -ENOMEM; } /* diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index aa6b490aa471..10af1e7524fb 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -203,6 +203,23 @@ struct cpu_map *cpu_map__dummy_new(void) return cpus; } +struct cpu_map *cpu_map__empty_new(int nr) +{ + struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int) * nr); + + if (cpus != NULL) { + int i; + + cpus->nr = nr; + for (i = 0; i < nr; i++) + cpus->map[i] = -1; + + atomic_set(&cpus->refcnt, 1); + } + + return cpus; +} + static void cpu_map__delete(struct cpu_map *map) { if (map) { diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index f1bcd2cfa164..85f7772457fa 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h @@ -15,6 +15,7 @@ struct cpu_map { }; struct cpu_map *cpu_map__new(const char *cpu_list); +struct cpu_map *cpu_map__empty_new(int nr); struct cpu_map *cpu_map__dummy_new(void); struct cpu_map *cpu_map__read(FILE *file); size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index ab05fa52a5cd..3ac4ee9c6a6e 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -652,6 +652,15 @@ static void apply_config_terms(struct perf_evsel *evsel, case PERF_EVSEL__CONFIG_TERM_STACK_USER: dump_size = term->val.stack_user; break; + case PERF_EVSEL__CONFIG_TERM_INHERIT: + /* + * attr->inherit should has already been set by + * perf_evsel__config. If user explicitly set + * inherit using config terms, override global + * opt->no_inherit setting. + */ + attr->inherit = term->val.inherit ? 1 : 0; + break; default: break; } diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 02a5fed8d924..1e8ff1906f71 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -43,6 +43,7 @@ enum { PERF_EVSEL__CONFIG_TERM_TIME, PERF_EVSEL__CONFIG_TERM_CALLGRAPH, PERF_EVSEL__CONFIG_TERM_STACK_USER, + PERF_EVSEL__CONFIG_TERM_INHERIT, PERF_EVSEL__CONFIG_TERM_MAX, }; @@ -55,6 +56,7 @@ struct perf_evsel_config_term { bool time; char *callgraph; u64 stack_user; + bool inherit; } val; }; @@ -90,9 +92,9 @@ struct perf_evsel { double scale; const char *unit; struct event_format *tp_format; + off_t id_offset; union { void *priv; - off_t id_offset; u64 db_id; }; struct cgroup_sel *cgrp; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 991bbd469bea..72abcf254ccb 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -666,6 +666,12 @@ do { \ case PARSE_EVENTS__TERM_TYPE_STACKSIZE: CHECK_TYPE_VAL(NUM); break; + case PARSE_EVENTS__TERM_TYPE_INHERIT: + CHECK_TYPE_VAL(NUM); + break; + case PARSE_EVENTS__TERM_TYPE_NOINHERIT: + CHECK_TYPE_VAL(NUM); + break; case PARSE_EVENTS__TERM_TYPE_NAME: CHECK_TYPE_VAL(STR); break; @@ -701,6 +707,8 @@ static int config_term_tracepoint(struct perf_event_attr *attr, switch (term->type_term) { case PARSE_EVENTS__TERM_TYPE_CALLGRAPH: case PARSE_EVENTS__TERM_TYPE_STACKSIZE: + case PARSE_EVENTS__TERM_TYPE_INHERIT: + case PARSE_EVENTS__TERM_TYPE_NOINHERIT: return config_term_common(attr, term, err); default: if (err) { @@ -764,6 +772,12 @@ do { \ case PARSE_EVENTS__TERM_TYPE_STACKSIZE: ADD_CONFIG_TERM(STACK_USER, stack_user, term->val.num); break; + case PARSE_EVENTS__TERM_TYPE_INHERIT: + ADD_CONFIG_TERM(INHERIT, inherit, term->val.num ? 1 : 0); + break; + case PARSE_EVENTS__TERM_TYPE_NOINHERIT: + ADD_CONFIG_TERM(INHERIT, inherit, term->val.num ? 0 : 1); + break; default: break; } diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index f13d3ccda444..13c9063513eb 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -67,6 +67,8 @@ enum { PARSE_EVENTS__TERM_TYPE_TIME, PARSE_EVENTS__TERM_TYPE_CALLGRAPH, PARSE_EVENTS__TERM_TYPE_STACKSIZE, + PARSE_EVENTS__TERM_TYPE_NOINHERIT, + PARSE_EVENTS__TERM_TYPE_INHERIT }; struct parse_events_term { diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index be244573a02e..8d0de5b2991d 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -187,6 +187,8 @@ branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); } call-graph { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CALLGRAPH); } stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); } +inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); } +no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } , { return ','; } "/" { BEGIN(INITIAL); return '/'; } {name_minus} { return str(yyscanner, PE_NAME); } diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index 22c2806bda98..9fca09296eb3 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c @@ -7,6 +7,8 @@ #define OPT_SHORT 1 #define OPT_UNSET 2 +static struct strbuf error_buf = STRBUF_INIT; + static int opterror(const struct option *opt, const char *reason, int flags) { if (flags & OPT_SHORT) @@ -540,9 +542,11 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o exit(130); default: /* PARSE_OPT_UNKNOWN */ if (ctx.argv[0][1] == '-') { - error("unknown option `%s'", ctx.argv[0] + 2); + strbuf_addf(&error_buf, "unknown option `%s'", + ctx.argv[0] + 2); } else { - error("unknown switch `%c'", *ctx.opt); + strbuf_addf(&error_buf, "unknown switch `%c'", + *ctx.opt); } usage_with_options(usagestr, options); } @@ -691,8 +695,21 @@ static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx for (i = 1; i < ctx->argc; ++i) { const char *arg = ctx->argv[i]; - if (arg[0] != '-') + if (arg[0] != '-') { + if (arg[1] == '\0') { + if (arg[0] == opt->short_name) + return true; + continue; + } + + if (opt->long_name && strcmp(opt->long_name, arg) == 0) + return true; + + if (opt->help && strcasestr(opt->help, arg) != NULL) + return true; + continue; + } if (arg[1] == opt->short_name || (arg[1] == '-' && opt->long_name && strcmp(opt->long_name, arg + 2) == 0)) @@ -711,6 +728,13 @@ int usage_with_options_internal(const char * const *usagestr, if (!usagestr) return PARSE_OPT_HELP; + setup_pager(); + + if (strbuf_avail(&error_buf)) { + fprintf(stderr, " Error: %s\n", error_buf.buf); + strbuf_release(&error_buf); + } + fprintf(stderr, "\n Usage: %s\n", *usagestr++); while (*usagestr && **usagestr) fprintf(stderr, " or: %s\n", *usagestr++); @@ -749,6 +773,21 @@ void usage_with_options(const char * const *usagestr, exit(129); } +void usage_with_options_msg(const char * const *usagestr, + const struct option *opts, const char *fmt, ...) +{ + va_list ap; + + exit_browser(false); + + va_start(ap, fmt); + strbuf_addv(&error_buf, fmt, ap); + va_end(ap); + + usage_with_options_internal(usagestr, opts, 0, NULL); + exit(129); +} + int parse_options_usage(const char * const *usagestr, const struct option *opts, const char *optstr, bool short_opt) @@ -770,24 +809,23 @@ int parse_options_usage(const char * const *usagestr, opt: for ( ; opts->type != OPTION_END; opts++) { if (short_opt) { - if (opts->short_name == *optstr) + if (opts->short_name == *optstr) { + print_option_help(opts, 0); break; + } continue; } if (opts->long_name == NULL) continue; - if (!prefixcmp(optstr, opts->long_name)) - break; - if (!prefixcmp(optstr, "no-") && - !prefixcmp(optstr + 3, opts->long_name)) - break; + if (!prefixcmp(opts->long_name, optstr)) + print_option_help(opts, 0); + if (!prefixcmp("no-", optstr) && + !prefixcmp(opts->long_name, optstr + 3)) + print_option_help(opts, 0); } - if (opts->type != OPTION_END) - print_option_help(opts, 0); - return PARSE_OPT_HELP; } diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h index 367d8b816cc7..a8e407bc251e 100644 --- a/tools/perf/util/parse-options.h +++ b/tools/perf/util/parse-options.h @@ -111,6 +111,7 @@ struct option { #define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) } #define OPT_BIT(s, l, v, h, b) { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h), .defval = (b) } #define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h) } +#define OPT_BOOLEAN_FLAG(s, l, v, h, f) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h), .flags = (f) } #define OPT_BOOLEAN_SET(s, l, v, os, h) \ { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), \ .value = check_vtype(v, bool *), .help = (h), \ @@ -160,6 +161,10 @@ extern int parse_options_subcommand(int argc, const char **argv, extern NORETURN void usage_with_options(const char * const *usagestr, const struct option *options); +extern NORETURN __attribute__((format(printf,3,4))) +void usage_with_options_msg(const char * const *usagestr, + const struct option *options, + const char *fmt, ...); /*----- incremantal advanced APIs -----*/ diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c index 4abe23550c73..25671fa16618 100644 --- a/tools/perf/util/strbuf.c +++ b/tools/perf/util/strbuf.c @@ -82,23 +82,22 @@ void strbuf_add(struct strbuf *sb, const void *data, size_t len) strbuf_setlen(sb, sb->len + len); } -void strbuf_addf(struct strbuf *sb, const char *fmt, ...) +void strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap) { int len; - va_list ap; + va_list ap_saved; if (!strbuf_avail(sb)) strbuf_grow(sb, 64); - va_start(ap, fmt); + + va_copy(ap_saved, ap); len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); - va_end(ap); if (len < 0) die("your vsnprintf is broken"); if (len > strbuf_avail(sb)) { strbuf_grow(sb, len); - va_start(ap, fmt); - len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); - va_end(ap); + len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved); + va_end(ap_saved); if (len > strbuf_avail(sb)) { die("this should not happen, your vsnprintf is broken"); } @@ -106,6 +105,15 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...) strbuf_setlen(sb, sb->len + len); } +void strbuf_addf(struct strbuf *sb, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + strbuf_addv(sb, fmt, ap); + va_end(ap); +} + ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint) { size_t oldlen = sb->len; diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h index 436ac319f6c7..529f2f035249 100644 --- a/tools/perf/util/strbuf.h +++ b/tools/perf/util/strbuf.h @@ -39,6 +39,7 @@ */ #include <assert.h> +#include <stdarg.h> extern char strbuf_slopbuf[]; struct strbuf { @@ -85,6 +86,7 @@ static inline void strbuf_addstr(struct strbuf *sb, const char *s) { __attribute__((format(printf,2,3))) extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...); +extern void strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap); /* XXX: if read fails, any partial read is undone */ extern ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint); diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index fd8477cacf88..48906333a858 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c @@ -337,7 +337,7 @@ int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, symbol_filter_t filter __maybe_unused, int kmodule __maybe_unused) { - unsigned char *build_id[BUILD_ID_SIZE]; + unsigned char build_id[BUILD_ID_SIZE]; int ret; ret = fd__is_64_bit(ss->fd); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e7bf0c46918d..b4cc7662677e 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -680,7 +680,7 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, pos->start -= curr_map->start - curr_map->pgoff; if (pos->end) pos->end -= curr_map->start - curr_map->pgoff; - if (curr_map != map) { + if (curr_map->dso != map->dso) { rb_erase_init(&pos->rb_node, root); symbols__insert( &curr_map->dso->symbols[curr_map->type], @@ -1406,6 +1406,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) struct symsrc ss_[2]; struct symsrc *syms_ss = NULL, *runtime_ss = NULL; bool kmod; + unsigned char build_id[BUILD_ID_SIZE]; pthread_mutex_lock(&dso->lock); @@ -1461,6 +1462,14 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE || dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; + + /* + * Read the build id if possible. This is required for + * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work + */ + if (filename__read_build_id(dso->name, build_id, BUILD_ID_SIZE) > 0) + dso__set_build_id(dso, build_id); + /* * Iterate over candidate debug images. * Keep track of "interesting" ones (those which have a symtab, dynsym, |