perf config: Add core.hybrid-merge to configure event merging

Provide a core.hybrid-merge configuration option in .perfconfig to allow
enabling hybrid event aggregation by default, avoiding the need to pass
--hybrid-merge explicitly on every invocation.

The config value is a default rather than an explicit request, so with
--hierarchy it is ignored with a warning, while giving both --hierarchy
and --hybrid-merge on the command line remains an error.  For the same
reason it is silently ignored when there are no events to merge, as
would be the case on any machine with a single core PMU, whereas an
explicit --hybrid-merge still warns. Record whether the option came from
the command line in symbol_conf so both can tell the two apart.

'perf stat' has its own merging options for counting, the sampling
core.hybrid-merge deliberately doesn't alter it and its --hybrid-merge
must still be given explicitly.

Signed-off-by: Ian Rogers <irogers@google.com>
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Ian Rogers 2026-09-16 22:07:06 -07:00 committed by Arnaldo Carvalho de Melo
parent 59eca52494
commit 5c8edd351d
5 changed files with 62 additions and 14 deletions

View File

@ -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:

View File

@ -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) {

View File

@ -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) {

View File

@ -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;
}

View File

@ -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,