diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt index 9b223f892829..6cff6f26af8d 100644 --- a/tools/perf/Documentation/perf-config.txt +++ b/tools/perf/Documentation/perf-config.txt @@ -217,6 +217,16 @@ core.*:: Sets a timeout (in milliseconds) for parsing 'addr2line' output. The default timeout is 5s. + hybrid-merge:: + Merge matching events from all hybrid core PMUs into one display + by default. For example, if a wildcard expands to run on both p-cores and + e-cores, this aggregates them into a single view. This applies to + 'perf report' and 'perf top', it is ignored with '--hierarchy' and + doesn't alter 'perf stat' where '--hybrid-merge' must be given + explicitly. As a default it is silently ignored when there is + nothing to merge, such as on a machine with a single core PMU, + whereas an explicit '--hybrid-merge' warns. + tui.*, gtk.*:: Subcommands that can be configured here are 'top', 'report' and 'annotate'. These values are booleans, for example: diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index bda4836fc524..57225bc87731 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -1120,7 +1120,13 @@ static int __cmd_report(struct report *rep) if (evlist__can_merge_hybrid(session->evlist, env)) { evlist__merge_hybrid(session->evlist, env); evlist__merge_hists_hybrid(session->evlist, false); - } else { + } else if (symbol_conf.hybrid_merge_set) { + /* + * Only an explicit --hybrid-merge warns. A + * core.hybrid-merge default is silent, as most + * machines aren't hybrid and there is nothing the + * user needs to do about it. + */ ui__warning("--hybrid-merge: no events to merge across core PMUs\n"); } } @@ -1460,8 +1466,9 @@ int cmd_report(int argc, const char **argv) parse_branch_mode), OPT_BOOLEAN(0, "branch-history", &branch_call_mode, "add last branch records to call history"), - OPT_BOOLEAN(0, "hybrid-merge", &symbol_conf.hybrid_merge, - "merge the same event across hybrid core PMUs"), + OPT_BOOLEAN_SET(0, "hybrid-merge", &symbol_conf.hybrid_merge, + &symbol_conf.hybrid_merge_set, + "merge the same event across hybrid core PMUs"), OPT_STRING(0, "objdump", &objdump_path, "path", "objdump binary to use for disassembly and annotations"), OPT_STRING(0, "addr2line", &addr2line_path, "path", @@ -1562,9 +1569,14 @@ int cmd_report(int argc, const char **argv) } if (symbol_conf.report_hierarchy && symbol_conf.hybrid_merge) { - pr_err("Error: --hierarchy and --hybrid-merge are mutually exclusive.\n"); - ret = -EINVAL; - goto exit; + if (symbol_conf.hybrid_merge_set) { + pr_err("Error: --hierarchy and --hybrid-merge are mutually exclusive.\n"); + ret = -EINVAL; + goto exit; + } + /* A config file default shouldn't fail an explicit option. */ + pr_warning("core.hybrid-merge ignored: --hierarchy cannot display merged hybrid events\n"); + symbol_conf.hybrid_merge = false; } if (disassembler_style) { diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 3bb3337f1244..a3442d2d6edf 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1314,9 +1314,11 @@ static int __cmd_top(struct perf_top *top) } /* - * Use global stat_config that is zero meaning aggr_mode is AGGR_NONE - * and hybrid_merge is false. + * Use global stat_config that is zero meaning aggr_mode is AGGR_NONE. + * Merging affects the event names as merged events share a name, all + * other stat_config behavior is unwanted here. */ + stat_config.hybrid_merge = symbol_conf.hybrid_merge; evlist__uniquify_evsel_names(top->evlist, &stat_config); ret = perf_top__start_counters(top); if (ret) @@ -1340,7 +1342,13 @@ static int __cmd_top(struct perf_top *top) if (evlist__can_merge_hybrid(top->evlist, /*env=*/NULL)) { evlist__merge_hybrid(top->evlist, /*env=*/NULL); evlist__merge_hists_hybrid(top->evlist, false); - } else { + } else if (symbol_conf.hybrid_merge_set) { + /* + * Only an explicit --hybrid-merge warns. A + * core.hybrid-merge default is silent, as most + * machines aren't hybrid and there is nothing the + * user needs to do about it. + */ ui__warning("--hybrid-merge: no events to merge across core PMUs\n"); } } @@ -1500,8 +1508,9 @@ int cmd_top(int argc, const char **argv) OPT_CALLBACK('e', "event", &parse_events_option_args, "event", "event selector. use 'perf list' to list available events", parse_events_option), - OPT_BOOLEAN(0, "hybrid-merge", &symbol_conf.hybrid_merge, - "merge the same event across hybrid core PMUs"), + OPT_BOOLEAN_SET(0, "hybrid-merge", &symbol_conf.hybrid_merge, + &symbol_conf.hybrid_merge_set, + "merge the same event across hybrid core PMUs"), OPT_CALLBACK(0, "filter", &top.evlist, "filter", "event filter", parse_filter), OPT_U64('c', "count", &opts->user_interval, "event period to sample"), @@ -1691,9 +1700,14 @@ int cmd_top(int argc, const char **argv) usage_with_options(top_usage, options); if (symbol_conf.report_hierarchy && symbol_conf.hybrid_merge) { - pr_err("Error: --hierarchy and --hybrid-merge are mutually exclusive.\n"); - status = -EINVAL; - goto out_put_evlist; + if (symbol_conf.hybrid_merge_set) { + pr_err("Error: --hierarchy and --hybrid-merge are mutually exclusive.\n"); + status = -EINVAL; + goto out_put_evlist; + } + /* A config file default shouldn't fail an explicit option. */ + pr_warning("core.hybrid-merge ignored: --hierarchy cannot display merged hybrid events\n"); + symbol_conf.hybrid_merge = false; } if (disassembler_style) { diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index b2972c35c1ec..8fe43b032e9a 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -470,6 +470,16 @@ static int perf_default_core_config(const char *var, const char *value) if (!strcmp(var, "core.addr2line-disable-warn")) symbol_conf.addr2line_disable_warn = perf_config_bool(var, value); + if (!strcmp(var, "core.hybrid-merge")) { + /* + * Note, this is for sampling tools like perf report and top. + * perf stat has its own merging options and the + * stat_config.hybrid_merge of "perf stat --hybrid-merge" is + * deliberately not set here. + */ + symbol_conf.hybrid_merge = perf_config_bool(var, value); + } + /* Add other config variables here. */ return 0; } diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h index 50317bdaf2b6..37d35f42dcc1 100644 --- a/tools/perf/util/symbol_conf.h +++ b/tools/perf/util/symbol_conf.h @@ -39,6 +39,8 @@ enum symbol__weight_mode { struct symbol_conf { bool hybrid_merge; + /* Was hybrid_merge given on the command line rather than in a config file? */ + bool hybrid_merge_set; bool nanosecs; unsigned short priv_size; bool try_vmlinux_path,