perf kvm: Factor out kvm_need_default_arch_event()

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.

Tested-by: Ian Rogers <irogers@google.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
This commit is contained in:
Namhyung Kim
2026-07-01 12:41:48 -07:00
parent 55caa65301
commit d12a0135e8
5 changed files with 69 additions and 60 deletions

View File

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

View File

@@ -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];
argv[j++] = strdup("-e");
argv[j++] = strdup("trace_imc/trace_cycles/");
*argc += 2;
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;
}
}
free(tmp);
return 0;
}

View File

@@ -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;
int ret = 0, j = *argc;
const struct option event_options[] = {
OPT_BOOLEAN('e', "event", &event, NULL),
OPT_BOOLEAN(0, "pfm-events", &event, NULL),
OPT_END()
};
argv[j++] = STRDUP_FAIL_EXIT("-e");
argv[j++] = STRDUP_FAIL_EXIT("cycles");
*argc += 2;
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;
}
free(tmp);
return 0;
EXIT:
free(tmp);
return ret;
}

View File

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

View File

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