[PATCH v2 1/6] perf kvm: Factor out kvm_need_default_arch_event()

From: Namhyung Kim

Date: Tue Jun 23 2026 - 15:15:46 EST


The kvm_add_default_arch_event() has a similar logic in each arch to
check if there's an existing command line option for events. Let's
check it in the generic code and remove the duplication.

Signed-off-by: Namhyung Kim <namhyung@xxxxxxxxxx>
---
tools/perf/builtin-kvm.c | 17 +++++---
.../util/kvm-stat-arch/kvm-stat-powerpc.c | 31 +++-----------
tools/perf/util/kvm-stat-arch/kvm-stat-x86.c | 34 +++------------
tools/perf/util/kvm-stat.c | 41 +++++++++++++++++++
tools/perf/util/kvm-stat.h | 8 ++++
5 files changed, 70 insertions(+), 61 deletions(-)

diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 2c6aef1e13a04cf2..2f00cc1fd1c7cdbd 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -51,6 +51,7 @@
#include <termios.h>
#include <semaphore.h>
#include <signal.h>
+#include <stdlib.h>
#include <math.h>
#include <perf/mmap.h>

@@ -2014,9 +2015,11 @@ static int __cmd_record(const char *file_name, int argc, const char **argv)

BUG_ON(i + 2 != rec_argc);

- ret = kvm_add_default_arch_event(EM_HOST, &i, rec_argv);
- if (ret)
- goto EXIT;
+ if (kvm_need_default_arch_event(EM_HOST, argc, argv)) {
+ ret = kvm_add_default_arch_event(EM_HOST, &i, rec_argv);
+ if (ret)
+ goto EXIT;
+ }

ret = cmd_record(i, rec_argv);

@@ -2101,9 +2104,11 @@ static int __cmd_top(int argc, const char **argv)

BUG_ON(i != argc);

- ret = kvm_add_default_arch_event(EM_HOST, &i, rec_argv);
- if (ret)
- goto EXIT;
+ if (kvm_need_default_arch_event(EM_HOST, argc, argv)) {
+ ret = kvm_add_default_arch_event(EM_HOST, &i, rec_argv);
+ if (ret)
+ goto EXIT;
+ }

ret = cmd_top(i, rec_argv);

diff --git a/tools/perf/util/kvm-stat-arch/kvm-stat-powerpc.c b/tools/perf/util/kvm-stat-arch/kvm-stat-powerpc.c
index 96d9c4ae020940f0..8d4133c35c12f14b 100644
--- a/tools/perf/util/kvm-stat-arch/kvm-stat-powerpc.c
+++ b/tools/perf/util/kvm-stat-arch/kvm-stat-powerpc.c
@@ -9,7 +9,6 @@

#include "book3s_hv_exits.h"
#include "book3s_hcalls.h"
-#include <subcmd/parse-options.h>

#define NR_TPS 4

@@ -177,35 +176,15 @@ int __cpu_isa_init_powerpc(struct perf_kvm_stat *kvm)
*/
int __kvm_add_default_arch_event_powerpc(int *argc, const char **argv)
{
- const char **tmp;
- bool event = false;
- int i, j = *argc;
+ int j = *argc;

- const struct option event_options[] = {
- OPT_BOOLEAN('e', "event", &event, NULL),
- OPT_END()
- };
-
- tmp = calloc(j + 1, sizeof(char *));
- if (!tmp)
+ if (!perf_pmus__have_event("trace_imc", "trace_cycles"))
return -EINVAL;

- for (i = 0; i < j; i++)
- tmp[i] = argv[i];
-
- parse_options(j, tmp, event_options, NULL, PARSE_OPT_KEEP_UNKNOWN);
- if (!event) {
- if (perf_pmus__have_event("trace_imc", "trace_cycles")) {
- argv[j++] = strdup("-e");
- argv[j++] = strdup("trace_imc/trace_cycles/");
- *argc += 2;
- } else {
- free(tmp);
- return -EINVAL;
- }
- }
+ argv[j++] = strdup("-e");
+ argv[j++] = strdup("trace_imc/trace_cycles/");
+ *argc += 2;

- free(tmp);
return 0;
}

diff --git a/tools/perf/util/kvm-stat-arch/kvm-stat-x86.c b/tools/perf/util/kvm-stat-arch/kvm-stat-x86.c
index 788d216f0852147d..46f9a0adcb608aab 100644
--- a/tools/perf/util/kvm-stat-arch/kvm-stat-x86.c
+++ b/tools/perf/util/kvm-stat-arch/kvm-stat-x86.c
@@ -7,7 +7,6 @@
#include "../../../arch/x86/include/uapi/asm/svm.h"
#include "../../../arch/x86/include/uapi/asm/vmx.h"
#include "../../../arch/x86/include/uapi/asm/kvm.h"
-#include <subcmd/parse-options.h>

define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS);
define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS);
@@ -211,38 +210,15 @@ int __cpu_isa_init_x86(struct perf_kvm_stat *kvm, const char *cpuid)
*/
int __kvm_add_default_arch_event_x86(int *argc, const char **argv)
{
- const char **tmp;
- bool event = false;
- int ret = 0, i, j = *argc;
-
- const struct option event_options[] = {
- OPT_BOOLEAN('e', "event", &event, NULL),
- OPT_BOOLEAN(0, "pfm-events", &event, NULL),
- OPT_END()
- };
-
- if (!x86__is_intel_cpu())
- return 0;
-
- tmp = calloc(j + 1, sizeof(char *));
- if (!tmp)
- return -ENOMEM;
-
- for (i = 0; i < j; i++)
- tmp[i] = argv[i];
-
- parse_options(j, tmp, event_options, NULL, PARSE_OPT_KEEP_UNKNOWN);
- if (!event) {
- argv[j++] = STRDUP_FAIL_EXIT("-e");
- argv[j++] = STRDUP_FAIL_EXIT("cycles");
- *argc += 2;
- }
+ int ret = 0, j = *argc;
+
+ argv[j++] = STRDUP_FAIL_EXIT("-e");
+ argv[j++] = STRDUP_FAIL_EXIT("cycles");
+ *argc += 2;

- free(tmp);
return 0;

EXIT:
- free(tmp);
return ret;
}

diff --git a/tools/perf/util/kvm-stat.c b/tools/perf/util/kvm-stat.c
index 755ab659a05c30f0..c571d2ed711a8345 100644
--- a/tools/perf/util/kvm-stat.c
+++ b/tools/perf/util/kvm-stat.c
@@ -1,8 +1,10 @@
// SPDX-License-Identifier: GPL-2.0
#include "debug.h"
+#include "env.h"
#include "evsel.h"
#include "kvm-stat.h"
#include <dwarf-regs.h>
+#include <subcmd/parse-options.h>

bool kvm_exit_event(struct evsel *evsel)
{
@@ -268,3 +270,42 @@ int kvm_add_default_arch_event(uint16_t e_machine, int *argc, const char **argv)
return 0;
}
}
+
+bool kvm_need_default_arch_event(uint16_t e_machine, int argc, const char **argv)
+{
+ const char **tmp_argv;
+ bool event = false;
+ int i;
+
+ const struct option event_options[] = {
+ OPT_BOOLEAN('e', "event", &event, NULL),
+ OPT_BOOLEAN(0, "pfm-events", &event, NULL),
+ OPT_END()
+ };
+
+ switch (e_machine) {
+ case EM_PPC:
+ case EM_PPC64:
+ break;
+ case EM_X86_64:
+ case EM_386:
+ if (!x86__is_intel_cpu())
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ /* parse_options() may change the argv, let's make a copy */
+ tmp_argv = calloc(argc + 1, sizeof(char *));
+ if (!tmp_argv)
+ return false;
+
+ for (i = 0; i < argc; i++)
+ tmp_argv[i] = argv[i];
+
+ parse_options(argc, tmp_argv, event_options, NULL, PARSE_OPT_KEEP_UNKNOWN);
+ free(tmp_argv);
+
+ return !event;
+}
diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h
index cdbd921a555f4e51..04f9f3193555972f 100644
--- a/tools/perf/util/kvm-stat.h
+++ b/tools/perf/util/kvm-stat.h
@@ -174,12 +174,20 @@ const char * const *__kvm_skip_events_riscv(void);
const char * const *__kvm_skip_events_s390(void);
const char * const *__kvm_skip_events_x86(void);

+bool kvm_need_default_arch_event(uint16_t e_machine, int argc, const char **argv);
int kvm_add_default_arch_event(uint16_t e_machine, int *argc, const char **argv);
int __kvm_add_default_arch_event_powerpc(int *argc, const char **argv);
int __kvm_add_default_arch_event_x86(int *argc, const char **argv);

#else /* !HAVE_LIBTRACEEVENT */

+static inline bool kvm_need_default_arch_event(uint16_t e_machine __maybe_unused,
+ int argc __maybe_unused,
+ const char **argv __maybe_unused)
+{
+ return false;
+}
+
static inline int kvm_add_default_arch_event(uint16_t e_machine __maybe_unused,
int *argc __maybe_unused,
const char **argv __maybe_unused)
--
2.55.0.rc0.799.gd6f94ed593-goog