aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2015-10-29 05:29:18 -0400
committerIngo Molnar <mingo@kernel.org>2015-10-29 05:29:18 -0400
commit6fc774ef4ceca99c35dd3fb230dab618f78c8d6f (patch)
treeecb640692bb7ab6a73fa92dad82d457aa0fe3bbd /tools
parent4341801873e23bbecee76dabb7c111e3693b900f (diff)
parent443f8c75e8d58d394b0e65b47e02e5cd8ed32b41 (diff)
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>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-report.txt2
-rw-r--r--tools/perf/builtin-evlist.c4
-rw-r--r--tools/perf/builtin-probe.c20
-rw-r--r--tools/perf/builtin-record.c11
-rw-r--r--tools/perf/builtin-report.c4
-rw-r--r--tools/perf/builtin-sched.c4
-rw-r--r--tools/perf/builtin-script.c8
-rw-r--r--tools/perf/builtin-stat.c59
-rw-r--r--tools/perf/util/cpumap.c17
-rw-r--r--tools/perf/util/cpumap.h1
-rw-r--r--tools/perf/util/evsel.c9
-rw-r--r--tools/perf/util/evsel.h4
-rw-r--r--tools/perf/util/parse-events.c14
-rw-r--r--tools/perf/util/parse-events.h2
-rw-r--r--tools/perf/util/parse-events.l2
-rw-r--r--tools/perf/util/parse-options.c62
-rw-r--r--tools/perf/util/parse-options.h5
-rw-r--r--tools/perf/util/strbuf.c22
-rw-r--r--tools/perf/util/strbuf.h2
-rw-r--r--tools/perf/util/symbol-minimal.c2
-rw-r--r--tools/perf/util/symbol.c11
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
29--show-nr-samples:: 29--show-nr-samples::
30 Show the number of samples for each symbol 30 Show the number of samples for each symbol
31 31
32--showcpuutilization:: 32--show-cpu-utilization::
33 Show sample percentage for different cpu modes. 33 Show sample percentage for different cpu modes.
34 34
35-T:: 35-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)
61 usage_with_options(evlist_usage, options); 61 usage_with_options(evlist_usage, options);
62 62
63 if (details.event_group && (details.verbose || details.freq)) { 63 if (details.event_group && (details.verbose || details.freq)) {
64 pr_err("--group option is not compatible with other options\n"); 64 usage_with_options_msg(evlist_usage, options,
65 usage_with_options(evlist_usage, options); 65 "--group option is not compatible with other options\n");
66 } 66 }
67 67
68 return __cmd_evlist(input_name, &details); 68 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)
528 PARSE_OPT_STOP_AT_NON_OPTION); 528 PARSE_OPT_STOP_AT_NON_OPTION);
529 if (argc > 0) { 529 if (argc > 0) {
530 if (strcmp(argv[0], "-") == 0) { 530 if (strcmp(argv[0], "-") == 0) {
531 pr_warning(" Error: '-' is not supported.\n"); 531 usage_with_options_msg(probe_usage, options,
532 usage_with_options(probe_usage, options); 532 "'-' is not supported.\n");
533 } 533 }
534 if (params.command && params.command != 'a') { 534 if (params.command && params.command != 'a') {
535 pr_warning(" Error: another command except --add is set.\n"); 535 usage_with_options_msg(probe_usage, options,
536 usage_with_options(probe_usage, options); 536 "another command except --add is set.\n");
537 } 537 }
538 ret = parse_probe_event_argv(argc, argv); 538 ret = parse_probe_event_argv(argc, argv);
539 if (ret < 0) { 539 if (ret < 0) {
@@ -562,8 +562,10 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
562 switch (params.command) { 562 switch (params.command) {
563 case 'l': 563 case 'l':
564 if (params.uprobes) { 564 if (params.uprobes) {
565 pr_warning(" Error: Don't use --list with --exec.\n"); 565 pr_err(" Error: Don't use --list with --exec.\n");
566 usage_with_options(probe_usage, options); 566 parse_options_usage(probe_usage, options, "l", true);
567 parse_options_usage(NULL, options, "x", true);
568 return -EINVAL;
567 } 569 }
568 ret = show_perf_probe_events(params.filter); 570 ret = show_perf_probe_events(params.filter);
569 if (ret < 0) 571 if (ret < 0)
@@ -603,8 +605,10 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
603 case 'a': 605 case 'a':
604 /* Ensure the last given target is used */ 606 /* Ensure the last given target is used */
605 if (params.target && !params.target_used) { 607 if (params.target && !params.target_used) {
606 pr_warning(" Error: -x/-m must follow the probe definitions.\n"); 608 pr_err(" Error: -x/-m must follow the probe definitions.\n");
607 usage_with_options(probe_usage, options); 609 parse_options_usage(probe_usage, options, "m", true);
610 parse_options_usage(NULL, options, "x", true);
611 return -EINVAL;
608 } 612 }
609 613
610 ret = perf_add_probe_events(params.events, params.nevents); 614 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)
1135 usage_with_options(record_usage, record_options); 1135 usage_with_options(record_usage, record_options);
1136 1136
1137 if (nr_cgroups && !rec->opts.target.system_wide) { 1137 if (nr_cgroups && !rec->opts.target.system_wide) {
1138 ui__error("cgroup monitoring only available in" 1138 usage_with_options_msg(record_usage, record_options,
1139 " system-wide mode\n"); 1139 "cgroup monitoring only available in system-wide mode");
1140 usage_with_options(record_usage, record_options); 1140
1141 } 1141 }
1142 if (rec->opts.record_switch_events && 1142 if (rec->opts.record_switch_events &&
1143 !perf_can_record_switch_events()) { 1143 !perf_can_record_switch_events()) {
1144 ui__error("kernel does not support recording context switch events (--switch-events option)\n"); 1144 ui__error("kernel does not support recording context switch events\n");
1145 usage_with_options(record_usage, record_options); 1145 parse_options_usage(record_usage, record_options, "switch-events", 0);
1146 return -EINVAL;
1146 } 1147 }
1147 1148
1148 if (!rec->itr) { 1149 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)
699 " Please refer the man page for the complete list."), 699 " Please refer the man page for the complete list."),
700 OPT_STRING('F', "fields", &field_order, "key[,keys...]", 700 OPT_STRING('F', "fields", &field_order, "key[,keys...]",
701 "output field(s): overhead, period, sample plus all of sort keys"), 701 "output field(s): overhead, period, sample plus all of sort keys"),
702 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 702 OPT_BOOLEAN(0, "show-cpu-utilization", &symbol_conf.show_cpu_utilization,
703 "Show sample percentage for different cpu modes"), 703 "Show sample percentage for different cpu modes"),
704 OPT_BOOLEAN_FLAG(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
705 "Show sample percentage for different cpu modes", PARSE_OPT_HIDDEN),
704 OPT_STRING('p', "parent", &parent_pattern, "regex", 706 OPT_STRING('p', "parent", &parent_pattern, "regex",
705 "regex filter to identify parent, see: '--sort parent'"), 707 "regex filter to identify parent, see: '--sort parent'"),
706 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, 708 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
1728 for (tok = strtok_r(str, ", ", &tmp); 1728 for (tok = strtok_r(str, ", ", &tmp);
1729 tok; tok = strtok_r(NULL, ", ", &tmp)) { 1729 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1730 if (sort_dimension__add(tok, &sched->sort_list) < 0) { 1730 if (sort_dimension__add(tok, &sched->sort_list) < 0) {
1731 error("Unknown --sort key: `%s'", tok); 1731 usage_with_options_msg(usage_msg, options,
1732 usage_with_options(usage_msg, options); 1732 "Unknown --sort key: `%s'", tok);
1733 } 1733 }
1734 } 1734 }
1735 1735
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)
1767 rep_script_path = get_script_path(argv[0], REPORT_SUFFIX); 1767 rep_script_path = get_script_path(argv[0], REPORT_SUFFIX);
1768 1768
1769 if (!rec_script_path && !rep_script_path) { 1769 if (!rec_script_path && !rep_script_path) {
1770 fprintf(stderr, " Couldn't find script %s\n\n See perf" 1770 usage_with_options_msg(script_usage, options,
1771 "Couldn't find script `%s'\n\n See perf"
1771 " script -l for available scripts.\n", argv[0]); 1772 " script -l for available scripts.\n", argv[0]);
1772 usage_with_options(script_usage, options);
1773 } 1773 }
1774 1774
1775 if (is_top_script(argv[0])) { 1775 if (is_top_script(argv[0])) {
@@ -1780,10 +1780,10 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1780 rep_args = has_required_arg(rep_script_path); 1780 rep_args = has_required_arg(rep_script_path);
1781 rec_args = (argc - 1) - rep_args; 1781 rec_args = (argc - 1) - rep_args;
1782 if (rec_args < 0) { 1782 if (rec_args < 0) {
1783 fprintf(stderr, " %s script requires options." 1783 usage_with_options_msg(script_usage, options,
1784 "`%s' script requires options."
1784 "\n\n See perf script -l for available " 1785 "\n\n See perf script -l for available "
1785 "scripts and options.\n", argv[0]); 1786 "scripts and options.\n", argv[0]);
1786 usage_with_options(script_usage, options);
1787 } 1787 }
1788 } 1788 }
1789 1789
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 = {
100 .uid = UINT_MAX, 100 .uid = UINT_MAX,
101}; 101};
102 102
103typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu);
104
103static int run_count = 1; 105static int run_count = 1;
104static bool no_inherit = false; 106static bool no_inherit = false;
105static volatile pid_t child_pid = -1; 107static volatile pid_t child_pid = -1;
@@ -119,7 +121,7 @@ static unsigned int unit_width = 4; /* strlen("unit") */
119static bool forever = false; 121static bool forever = false;
120static struct timespec ref_time; 122static struct timespec ref_time;
121static struct cpu_map *aggr_map; 123static struct cpu_map *aggr_map;
122static int (*aggr_get_id)(struct cpu_map *m, int cpu); 124static aggr_get_id_t aggr_get_id;
123 125
124static volatile int done = 0; 126static volatile int done = 0;
125 127
@@ -954,22 +956,63 @@ static int perf_stat__get_core(struct cpu_map *map, int cpu)
954 return cpu_map__get_core(map, cpu, NULL); 956 return cpu_map__get_core(map, cpu, NULL);
955} 957}
956 958
959static int cpu_map__get_max(struct cpu_map *map)
960{
961 int i, max = -1;
962
963 for (i = 0; i < map->nr; i++) {
964 if (map->map[i] > max)
965 max = map->map[i];
966 }
967
968 return max;
969}
970
971static struct cpu_map *cpus_aggr_map;
972
973static int perf_stat__get_aggr(aggr_get_id_t get_id, struct cpu_map *map, int idx)
974{
975 int cpu;
976
977 if (idx >= map->nr)
978 return -1;
979
980 cpu = map->map[idx];
981
982 if (cpus_aggr_map->map[cpu] == -1)
983 cpus_aggr_map->map[cpu] = get_id(map, idx);
984
985 return cpus_aggr_map->map[cpu];
986}
987
988static int perf_stat__get_socket_cached(struct cpu_map *map, int idx)
989{
990 return perf_stat__get_aggr(perf_stat__get_socket, map, idx);
991}
992
993static int perf_stat__get_core_cached(struct cpu_map *map, int idx)
994{
995 return perf_stat__get_aggr(perf_stat__get_core, map, idx);
996}
997
957static int perf_stat_init_aggr_mode(void) 998static int perf_stat_init_aggr_mode(void)
958{ 999{
1000 int nr;
1001
959 switch (stat_config.aggr_mode) { 1002 switch (stat_config.aggr_mode) {
960 case AGGR_SOCKET: 1003 case AGGR_SOCKET:
961 if (cpu_map__build_socket_map(evsel_list->cpus, &aggr_map)) { 1004 if (cpu_map__build_socket_map(evsel_list->cpus, &aggr_map)) {
962 perror("cannot build socket map"); 1005 perror("cannot build socket map");
963 return -1; 1006 return -1;
964 } 1007 }
965 aggr_get_id = perf_stat__get_socket; 1008 aggr_get_id = perf_stat__get_socket_cached;
966 break; 1009 break;
967 case AGGR_CORE: 1010 case AGGR_CORE:
968 if (cpu_map__build_core_map(evsel_list->cpus, &aggr_map)) { 1011 if (cpu_map__build_core_map(evsel_list->cpus, &aggr_map)) {
969 perror("cannot build core map"); 1012 perror("cannot build core map");
970 return -1; 1013 return -1;
971 } 1014 }
972 aggr_get_id = perf_stat__get_core; 1015 aggr_get_id = perf_stat__get_core_cached;
973 break; 1016 break;
974 case AGGR_NONE: 1017 case AGGR_NONE:
975 case AGGR_GLOBAL: 1018 case AGGR_GLOBAL:
@@ -978,7 +1021,15 @@ static int perf_stat_init_aggr_mode(void)
978 default: 1021 default:
979 break; 1022 break;
980 } 1023 }
981 return 0; 1024
1025 /*
1026 * The evsel_list->cpus is the base we operate on,
1027 * taking the highest cpu number to be the size of
1028 * the aggregation translate cpumap.
1029 */
1030 nr = cpu_map__get_max(evsel_list->cpus);
1031 cpus_aggr_map = cpu_map__empty_new(nr + 1);
1032 return cpus_aggr_map ? 0 : -ENOMEM;
982} 1033}
983 1034
984/* 1035/*
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)
203 return cpus; 203 return cpus;
204} 204}
205 205
206struct cpu_map *cpu_map__empty_new(int nr)
207{
208 struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int) * nr);
209
210 if (cpus != NULL) {
211 int i;
212
213 cpus->nr = nr;
214 for (i = 0; i < nr; i++)
215 cpus->map[i] = -1;
216
217 atomic_set(&cpus->refcnt, 1);
218 }
219
220 return cpus;
221}
222
206static void cpu_map__delete(struct cpu_map *map) 223static void cpu_map__delete(struct cpu_map *map)
207{ 224{
208 if (map) { 225 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 {
15}; 15};
16 16
17struct cpu_map *cpu_map__new(const char *cpu_list); 17struct cpu_map *cpu_map__new(const char *cpu_list);
18struct cpu_map *cpu_map__empty_new(int nr);
18struct cpu_map *cpu_map__dummy_new(void); 19struct cpu_map *cpu_map__dummy_new(void);
19struct cpu_map *cpu_map__read(FILE *file); 20struct cpu_map *cpu_map__read(FILE *file);
20size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); 21size_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,
652 case PERF_EVSEL__CONFIG_TERM_STACK_USER: 652 case PERF_EVSEL__CONFIG_TERM_STACK_USER:
653 dump_size = term->val.stack_user; 653 dump_size = term->val.stack_user;
654 break; 654 break;
655 case PERF_EVSEL__CONFIG_TERM_INHERIT:
656 /*
657 * attr->inherit should has already been set by
658 * perf_evsel__config. If user explicitly set
659 * inherit using config terms, override global
660 * opt->no_inherit setting.
661 */
662 attr->inherit = term->val.inherit ? 1 : 0;
663 break;
655 default: 664 default:
656 break; 665 break;
657 } 666 }
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 {
43 PERF_EVSEL__CONFIG_TERM_TIME, 43 PERF_EVSEL__CONFIG_TERM_TIME,
44 PERF_EVSEL__CONFIG_TERM_CALLGRAPH, 44 PERF_EVSEL__CONFIG_TERM_CALLGRAPH,
45 PERF_EVSEL__CONFIG_TERM_STACK_USER, 45 PERF_EVSEL__CONFIG_TERM_STACK_USER,
46 PERF_EVSEL__CONFIG_TERM_INHERIT,
46 PERF_EVSEL__CONFIG_TERM_MAX, 47 PERF_EVSEL__CONFIG_TERM_MAX,
47}; 48};
48 49
@@ -55,6 +56,7 @@ struct perf_evsel_config_term {
55 bool time; 56 bool time;
56 char *callgraph; 57 char *callgraph;
57 u64 stack_user; 58 u64 stack_user;
59 bool inherit;
58 } val; 60 } val;
59}; 61};
60 62
@@ -90,9 +92,9 @@ struct perf_evsel {
90 double scale; 92 double scale;
91 const char *unit; 93 const char *unit;
92 struct event_format *tp_format; 94 struct event_format *tp_format;
95 off_t id_offset;
93 union { 96 union {
94 void *priv; 97 void *priv;
95 off_t id_offset;
96 u64 db_id; 98 u64 db_id;
97 }; 99 };
98 struct cgroup_sel *cgrp; 100 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 { \
666 case PARSE_EVENTS__TERM_TYPE_STACKSIZE: 666 case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
667 CHECK_TYPE_VAL(NUM); 667 CHECK_TYPE_VAL(NUM);
668 break; 668 break;
669 case PARSE_EVENTS__TERM_TYPE_INHERIT:
670 CHECK_TYPE_VAL(NUM);
671 break;
672 case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
673 CHECK_TYPE_VAL(NUM);
674 break;
669 case PARSE_EVENTS__TERM_TYPE_NAME: 675 case PARSE_EVENTS__TERM_TYPE_NAME:
670 CHECK_TYPE_VAL(STR); 676 CHECK_TYPE_VAL(STR);
671 break; 677 break;
@@ -701,6 +707,8 @@ static int config_term_tracepoint(struct perf_event_attr *attr,
701 switch (term->type_term) { 707 switch (term->type_term) {
702 case PARSE_EVENTS__TERM_TYPE_CALLGRAPH: 708 case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
703 case PARSE_EVENTS__TERM_TYPE_STACKSIZE: 709 case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
710 case PARSE_EVENTS__TERM_TYPE_INHERIT:
711 case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
704 return config_term_common(attr, term, err); 712 return config_term_common(attr, term, err);
705 default: 713 default:
706 if (err) { 714 if (err) {
@@ -764,6 +772,12 @@ do { \
764 case PARSE_EVENTS__TERM_TYPE_STACKSIZE: 772 case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
765 ADD_CONFIG_TERM(STACK_USER, stack_user, term->val.num); 773 ADD_CONFIG_TERM(STACK_USER, stack_user, term->val.num);
766 break; 774 break;
775 case PARSE_EVENTS__TERM_TYPE_INHERIT:
776 ADD_CONFIG_TERM(INHERIT, inherit, term->val.num ? 1 : 0);
777 break;
778 case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
779 ADD_CONFIG_TERM(INHERIT, inherit, term->val.num ? 0 : 1);
780 break;
767 default: 781 default:
768 break; 782 break;
769 } 783 }
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 {
67 PARSE_EVENTS__TERM_TYPE_TIME, 67 PARSE_EVENTS__TERM_TYPE_TIME,
68 PARSE_EVENTS__TERM_TYPE_CALLGRAPH, 68 PARSE_EVENTS__TERM_TYPE_CALLGRAPH,
69 PARSE_EVENTS__TERM_TYPE_STACKSIZE, 69 PARSE_EVENTS__TERM_TYPE_STACKSIZE,
70 PARSE_EVENTS__TERM_TYPE_NOINHERIT,
71 PARSE_EVENTS__TERM_TYPE_INHERIT
70}; 72};
71 73
72struct parse_events_term { 74struct 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
187time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); } 187time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); }
188call-graph { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CALLGRAPH); } 188call-graph { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CALLGRAPH); }
189stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); } 189stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); }
190inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); }
191no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); }
190, { return ','; } 192, { return ','; }
191"/" { BEGIN(INITIAL); return '/'; } 193"/" { BEGIN(INITIAL); return '/'; }
192{name_minus} { return str(yyscanner, PE_NAME); } 194{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 @@
7#define OPT_SHORT 1 7#define OPT_SHORT 1
8#define OPT_UNSET 2 8#define OPT_UNSET 2
9 9
10static struct strbuf error_buf = STRBUF_INIT;
11
10static int opterror(const struct option *opt, const char *reason, int flags) 12static int opterror(const struct option *opt, const char *reason, int flags)
11{ 13{
12 if (flags & OPT_SHORT) 14 if (flags & OPT_SHORT)
@@ -540,9 +542,11 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o
540 exit(130); 542 exit(130);
541 default: /* PARSE_OPT_UNKNOWN */ 543 default: /* PARSE_OPT_UNKNOWN */
542 if (ctx.argv[0][1] == '-') { 544 if (ctx.argv[0][1] == '-') {
543 error("unknown option `%s'", ctx.argv[0] + 2); 545 strbuf_addf(&error_buf, "unknown option `%s'",
546 ctx.argv[0] + 2);
544 } else { 547 } else {
545 error("unknown switch `%c'", *ctx.opt); 548 strbuf_addf(&error_buf, "unknown switch `%c'",
549 *ctx.opt);
546 } 550 }
547 usage_with_options(usagestr, options); 551 usage_with_options(usagestr, options);
548 } 552 }
@@ -691,8 +695,21 @@ static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx
691 for (i = 1; i < ctx->argc; ++i) { 695 for (i = 1; i < ctx->argc; ++i) {
692 const char *arg = ctx->argv[i]; 696 const char *arg = ctx->argv[i];
693 697
694 if (arg[0] != '-') 698 if (arg[0] != '-') {
699 if (arg[1] == '\0') {
700 if (arg[0] == opt->short_name)
701 return true;
702 continue;
703 }
704
705 if (opt->long_name && strcmp(opt->long_name, arg) == 0)
706 return true;
707
708 if (opt->help && strcasestr(opt->help, arg) != NULL)
709 return true;
710
695 continue; 711 continue;
712 }
696 713
697 if (arg[1] == opt->short_name || 714 if (arg[1] == opt->short_name ||
698 (arg[1] == '-' && opt->long_name && strcmp(opt->long_name, arg + 2) == 0)) 715 (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,
711 if (!usagestr) 728 if (!usagestr)
712 return PARSE_OPT_HELP; 729 return PARSE_OPT_HELP;
713 730
731 setup_pager();
732
733 if (strbuf_avail(&error_buf)) {
734 fprintf(stderr, " Error: %s\n", error_buf.buf);
735 strbuf_release(&error_buf);
736 }
737
714 fprintf(stderr, "\n Usage: %s\n", *usagestr++); 738 fprintf(stderr, "\n Usage: %s\n", *usagestr++);
715 while (*usagestr && **usagestr) 739 while (*usagestr && **usagestr)
716 fprintf(stderr, " or: %s\n", *usagestr++); 740 fprintf(stderr, " or: %s\n", *usagestr++);
@@ -749,6 +773,21 @@ void usage_with_options(const char * const *usagestr,
749 exit(129); 773 exit(129);
750} 774}
751 775
776void usage_with_options_msg(const char * const *usagestr,
777 const struct option *opts, const char *fmt, ...)
778{
779 va_list ap;
780
781 exit_browser(false);
782
783 va_start(ap, fmt);
784 strbuf_addv(&error_buf, fmt, ap);
785 va_end(ap);
786
787 usage_with_options_internal(usagestr, opts, 0, NULL);
788 exit(129);
789}
790
752int parse_options_usage(const char * const *usagestr, 791int parse_options_usage(const char * const *usagestr,
753 const struct option *opts, 792 const struct option *opts,
754 const char *optstr, bool short_opt) 793 const char *optstr, bool short_opt)
@@ -770,24 +809,23 @@ int parse_options_usage(const char * const *usagestr,
770opt: 809opt:
771 for ( ; opts->type != OPTION_END; opts++) { 810 for ( ; opts->type != OPTION_END; opts++) {
772 if (short_opt) { 811 if (short_opt) {
773 if (opts->short_name == *optstr) 812 if (opts->short_name == *optstr) {
813 print_option_help(opts, 0);
774 break; 814 break;
815 }
775 continue; 816 continue;
776 } 817 }
777 818
778 if (opts->long_name == NULL) 819 if (opts->long_name == NULL)
779 continue; 820 continue;
780 821
781 if (!prefixcmp(optstr, opts->long_name)) 822 if (!prefixcmp(opts->long_name, optstr))
782 break; 823 print_option_help(opts, 0);
783 if (!prefixcmp(optstr, "no-") && 824 if (!prefixcmp("no-", optstr) &&
784 !prefixcmp(optstr + 3, opts->long_name)) 825 !prefixcmp(opts->long_name, optstr + 3))
785 break; 826 print_option_help(opts, 0);
786 } 827 }
787 828
788 if (opts->type != OPTION_END)
789 print_option_help(opts, 0);
790
791 return PARSE_OPT_HELP; 829 return PARSE_OPT_HELP;
792} 830}
793 831
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 {
111#define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) } 111#define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) }
112#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) } 112#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) }
113#define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h) } 113#define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h) }
114#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) }
114#define OPT_BOOLEAN_SET(s, l, v, os, h) \ 115#define OPT_BOOLEAN_SET(s, l, v, os, h) \
115 { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), \ 116 { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), \
116 .value = check_vtype(v, bool *), .help = (h), \ 117 .value = check_vtype(v, bool *), .help = (h), \
@@ -160,6 +161,10 @@ extern int parse_options_subcommand(int argc, const char **argv,
160 161
161extern NORETURN void usage_with_options(const char * const *usagestr, 162extern NORETURN void usage_with_options(const char * const *usagestr,
162 const struct option *options); 163 const struct option *options);
164extern NORETURN __attribute__((format(printf,3,4)))
165void usage_with_options_msg(const char * const *usagestr,
166 const struct option *options,
167 const char *fmt, ...);
163 168
164/*----- incremantal advanced APIs -----*/ 169/*----- incremantal advanced APIs -----*/
165 170
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)
82 strbuf_setlen(sb, sb->len + len); 82 strbuf_setlen(sb, sb->len + len);
83} 83}
84 84
85void strbuf_addf(struct strbuf *sb, const char *fmt, ...) 85void strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap)
86{ 86{
87 int len; 87 int len;
88 va_list ap; 88 va_list ap_saved;
89 89
90 if (!strbuf_avail(sb)) 90 if (!strbuf_avail(sb))
91 strbuf_grow(sb, 64); 91 strbuf_grow(sb, 64);
92 va_start(ap, fmt); 92
93 va_copy(ap_saved, ap);
93 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); 94 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
94 va_end(ap);
95 if (len < 0) 95 if (len < 0)
96 die("your vsnprintf is broken"); 96 die("your vsnprintf is broken");
97 if (len > strbuf_avail(sb)) { 97 if (len > strbuf_avail(sb)) {
98 strbuf_grow(sb, len); 98 strbuf_grow(sb, len);
99 va_start(ap, fmt); 99 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved);
100 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); 100 va_end(ap_saved);
101 va_end(ap);
102 if (len > strbuf_avail(sb)) { 101 if (len > strbuf_avail(sb)) {
103 die("this should not happen, your vsnprintf is broken"); 102 die("this should not happen, your vsnprintf is broken");
104 } 103 }
@@ -106,6 +105,15 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
106 strbuf_setlen(sb, sb->len + len); 105 strbuf_setlen(sb, sb->len + len);
107} 106}
108 107
108void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
109{
110 va_list ap;
111
112 va_start(ap, fmt);
113 strbuf_addv(sb, fmt, ap);
114 va_end(ap);
115}
116
109ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint) 117ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
110{ 118{
111 size_t oldlen = sb->len; 119 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 @@
39 */ 39 */
40 40
41#include <assert.h> 41#include <assert.h>
42#include <stdarg.h>
42 43
43extern char strbuf_slopbuf[]; 44extern char strbuf_slopbuf[];
44struct strbuf { 45struct strbuf {
@@ -85,6 +86,7 @@ static inline void strbuf_addstr(struct strbuf *sb, const char *s) {
85 86
86__attribute__((format(printf,2,3))) 87__attribute__((format(printf,2,3)))
87extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...); 88extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
89extern void strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap);
88 90
89/* XXX: if read fails, any partial read is undone */ 91/* XXX: if read fails, any partial read is undone */
90extern ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint); 92extern 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,
337 symbol_filter_t filter __maybe_unused, 337 symbol_filter_t filter __maybe_unused,
338 int kmodule __maybe_unused) 338 int kmodule __maybe_unused)
339{ 339{
340 unsigned char *build_id[BUILD_ID_SIZE]; 340 unsigned char build_id[BUILD_ID_SIZE];
341 int ret; 341 int ret;
342 342
343 ret = fd__is_64_bit(ss->fd); 343 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,
680 pos->start -= curr_map->start - curr_map->pgoff; 680 pos->start -= curr_map->start - curr_map->pgoff;
681 if (pos->end) 681 if (pos->end)
682 pos->end -= curr_map->start - curr_map->pgoff; 682 pos->end -= curr_map->start - curr_map->pgoff;
683 if (curr_map != map) { 683 if (curr_map->dso != map->dso) {
684 rb_erase_init(&pos->rb_node, root); 684 rb_erase_init(&pos->rb_node, root);
685 symbols__insert( 685 symbols__insert(
686 &curr_map->dso->symbols[curr_map->type], 686 &curr_map->dso->symbols[curr_map->type],
@@ -1406,6 +1406,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1406 struct symsrc ss_[2]; 1406 struct symsrc ss_[2];
1407 struct symsrc *syms_ss = NULL, *runtime_ss = NULL; 1407 struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
1408 bool kmod; 1408 bool kmod;
1409 unsigned char build_id[BUILD_ID_SIZE];
1409 1410
1410 pthread_mutex_lock(&dso->lock); 1411 pthread_mutex_lock(&dso->lock);
1411 1412
@@ -1461,6 +1462,14 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1461 dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE || 1462 dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
1462 dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; 1463 dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
1463 1464
1465
1466 /*
1467 * Read the build id if possible. This is required for
1468 * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work
1469 */
1470 if (filename__read_build_id(dso->name, build_id, BUILD_ID_SIZE) > 0)
1471 dso__set_build_id(dso, build_id);
1472
1464 /* 1473 /*
1465 * Iterate over candidate debug images. 1474 * Iterate over candidate debug images.
1466 * Keep track of "interesting" ones (those which have a symtab, dynsym, 1475 * Keep track of "interesting" ones (those which have a symtab, dynsym,