aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-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,