linux-perf-users.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3] perf kvm: Add kvm-stat for loongarch64
@ 2024-04-11 12:10 Bibo Mao
  2024-04-19  2:34 ` maobibo
  2024-05-07  6:10 ` maobibo
  0 siblings, 2 replies; 6+ messages in thread
From: Bibo Mao @ 2024-04-11 12:10 UTC (permalink / raw)
  To: Ming Wang, Huacai Chen
  Cc: Peter Zijlstra, Ingo Molnar, linux-kernel, linux-perf-users,
	Ian Rogers

Add support for 'perf kvm stat' on loongarch64 platform, now only
kvm exit event is supported.

Here is example output about "perf kvm --host stat report" command

   Event name   Samples   Sample%     Time (ns)   Time%   Mean Time (ns)
    Mem store     83969    51.00%     625697070   8.00%             7451
     Mem read     37641    22.00%     112485730   1.00%             2988
    Interrupt     15542     9.00%      20620190   0.00%             1326
        Iocsr     15207     9.00%      94296190   1.00%             6200
    Hypercall      4873     2.00%      12265280   0.00%             2516
         Idle      3713     2.00%    6322055860  87.00%          1702681
          FPU      1819     1.00%       2750300   0.00%             1511
       Ifecth       502     0.00%       1341740   0.00%             2672
   Mem modify       324     0.00%        602240   0.00%             1858
       Cpucfg        55     0.00%         77610   0.00%             1411
          Csr        12     0.00%         19690   0.00%             1640
         LASX         3     0.00%          4870   0.00%             1623
          LSX         2     0.00%          2100   0.00%             1050

Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
v2 --- v3:
  1. Add NULL check with cpuid in function get_cpuid()
  2. Add example output from /proc/cpuinfo before function get_cpuid()
v1 --- v2:
  1. Add child_ops for kvm exit event, split kvm:kvm_exit_gspr events
into cpucfg/csr/iocsr/idle child events by decoding detailed gspr
instruction.
  2. Remove some exception code type which does not happen in current
kvm implementation, such as meomry NR/NX/priviledge exception.
---
 tools/perf/arch/loongarch/Makefile        |   1 +
 tools/perf/arch/loongarch/util/Build      |   2 +
 tools/perf/arch/loongarch/util/header.c   |  88 ++++++++++++++
 tools/perf/arch/loongarch/util/kvm-stat.c | 135 ++++++++++++++++++++++
 4 files changed, 226 insertions(+)
 create mode 100644 tools/perf/arch/loongarch/util/header.c
 create mode 100644 tools/perf/arch/loongarch/util/kvm-stat.c

diff --git a/tools/perf/arch/loongarch/Makefile b/tools/perf/arch/loongarch/Makefile
index 3992a67a87d9..c89d6bb6b184 100644
--- a/tools/perf/arch/loongarch/Makefile
+++ b/tools/perf/arch/loongarch/Makefile
@@ -4,6 +4,7 @@ PERF_HAVE_DWARF_REGS := 1
 endif
 PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
 PERF_HAVE_JITDUMP := 1
+HAVE_KVM_STAT_SUPPORT := 1
 
 #
 # Syscall table generation for perf
diff --git a/tools/perf/arch/loongarch/util/Build b/tools/perf/arch/loongarch/util/Build
index d776125a2d06..b12d374d7096 100644
--- a/tools/perf/arch/loongarch/util/Build
+++ b/tools/perf/arch/loongarch/util/Build
@@ -1,5 +1,7 @@
+perf-y += header.o
 perf-y += perf_regs.o
 
 perf-$(CONFIG_DWARF)     += dwarf-regs.o
 perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
 perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
+perf-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
diff --git a/tools/perf/arch/loongarch/util/header.c b/tools/perf/arch/loongarch/util/header.c
new file mode 100644
index 000000000000..a4ed732b49c6
--- /dev/null
+++ b/tools/perf/arch/loongarch/util/header.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Implementation of get_cpuid().
+ *
+ * Author: Nikita Shubin <n.shubin@yadro.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <api/fs/fs.h>
+#include <errno.h>
+#include "util/debug.h"
+#include "util/header.h"
+
+/*
+ * Output example from /proc/cpuinfo
+ *   CPU Family              : Loongson-64bit
+ *   Model Name              : Loongson-3C5000
+ *   CPU Revision            : 0x11
+ */
+#define CPUINFO_MODEL	"Model Name"
+#define CPUINFO		"/proc/cpuinfo"
+static char *_get_field(const char *line)
+{
+	char *line2, *nl;
+
+	line2 = strrchr(line, ' ');
+	if (!line2)
+		return NULL;
+
+	line2++;
+	nl = strrchr(line, '\n');
+	if (!nl)
+		return NULL;
+
+	return strndup(line2, nl - line2);
+}
+
+static char *__get_cpuid(void)
+{
+	char *line, *model, *cpuid;
+	unsigned long line_sz;
+	FILE *file;
+
+	file = fopen(CPUINFO, "r");
+	if (file == NULL)
+		return cpuid;
+
+	line = model = cpuid = NULL;
+	while (getline(&line, &line_sz, file) != -1) {
+		if (strncmp(line, CPUINFO_MODEL, strlen(CPUINFO_MODEL)))
+			continue;
+
+		model = _get_field(line);
+		if (!model)
+			goto free;
+		break;
+	}
+
+	if (model && (asprintf(&cpuid, "%s", model) < 0))
+		cpuid = NULL;
+
+free:
+	fclose(file);
+	free(model);
+	return cpuid;
+}
+
+int get_cpuid(char *buffer, size_t sz)
+{
+	char *cpuid = __get_cpuid();
+	int ret = 0;
+
+	if (!cpuid)
+		return EINVAL;
+
+	if (sz >= strlen(cpuid))
+		scnprintf(buffer, sz, "%s", cpuid);
+	else
+		ret = ENOBUFS;
+	free(cpuid);
+	return ret;
+}
+
+char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
+{
+	return __get_cpuid();
+}
diff --git a/tools/perf/arch/loongarch/util/kvm-stat.c b/tools/perf/arch/loongarch/util/kvm-stat.c
new file mode 100644
index 000000000000..cc50adb0835a
--- /dev/null
+++ b/tools/perf/arch/loongarch/util/kvm-stat.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <errno.h>
+#include <memory.h>
+#include <errno.h>
+#include "util/kvm-stat.h"
+#include "util/parse-events.h"
+#include "util/debug.h"
+#include "util/evsel.h"
+#include "util/evlist.h"
+#include "util/pmus.h"
+
+#define LOONGARCH_EXCEPTION_INT		0
+#define LOONGARCH_EXCEPTION_PIL		1
+#define LOONGARCH_EXCEPTION_PIS		2
+#define LOONGARCH_EXCEPTION_PIF		3
+#define LOONGARCH_EXCEPTION_PME		4
+#define LOONGARCH_EXCEPTION_FPD		15
+#define LOONGARCH_EXCEPTION_SXD		16
+#define LOONGARCH_EXCEPTION_ASXD	17
+#define LOONGARCH_EXCEPTION_GSPR	22
+#define  LOONGARCH_EXCEPTION_CPUCFG	100
+#define  LOONGARCH_EXCEPTION_CSR	101
+#define  LOONGARCH_EXCEPTION_IOCSR	102
+#define  LOONGARCH_EXCEPTION_IDLE	103
+#define  LOONGARCH_EXCEPTION_OTHERS	104
+#define LOONGARCH_EXCEPTION_HVC		23
+
+#define loongarch_exception_type				\
+	{LOONGARCH_EXCEPTION_INT,  "Interrupt" },		\
+	{LOONGARCH_EXCEPTION_PIL,  "Mem read" },		\
+	{LOONGARCH_EXCEPTION_PIS,  "Mem store" },		\
+	{LOONGARCH_EXCEPTION_PIF,  "Ifecth" },			\
+	{LOONGARCH_EXCEPTION_PME,  "Mem modify" },		\
+	{LOONGARCH_EXCEPTION_FPD,  "FPU" },			\
+	{LOONGARCH_EXCEPTION_SXD,  "LSX" },			\
+	{LOONGARCH_EXCEPTION_ASXD, "LASX" },			\
+	{LOONGARCH_EXCEPTION_GSPR, "Privilege Error" },		\
+	{LOONGARCH_EXCEPTION_HVC,  "Hypercall" },		\
+	{LOONGARCH_EXCEPTION_CPUCFG, "Cpucfg" },		\
+	{LOONGARCH_EXCEPTION_CSR,    "Csr" },			\
+	{LOONGARCH_EXCEPTION_IOCSR,  "Iocsr" },			\
+	{LOONGARCH_EXCEPTION_IDLE,   "Idle" },			\
+	{LOONGARCH_EXCEPTION_OTHERS, "Others" }
+
+define_exit_reasons_table(loongarch_exit_reasons, loongarch_exception_type);
+
+const char *vcpu_id_str = "vcpu_id";
+const char *kvm_exit_reason = "reason";
+const char *kvm_entry_trace = "kvm:kvm_enter";
+const char *kvm_reenter_trace = "kvm:kvm_reenter";
+const char *kvm_exit_trace = "kvm:kvm_exit";
+const char *kvm_events_tp[] = {
+	"kvm:kvm_enter",
+	"kvm:kvm_reenter",
+	"kvm:kvm_exit",
+	"kvm:kvm_exit_gspr",
+	NULL,
+};
+
+static bool event_end(struct evsel *evsel,
+		struct perf_sample *sample __maybe_unused,
+		struct event_key *key __maybe_unused)
+{
+	/*
+	 * LoongArch kvm is different with other architectures
+	 *
+	 * There is kvm:kvm_reenter or kvm:kvm_enter event adjacent with
+	 * kvm:kvm_exit event.
+	 *   kvm:kvm_reenter means returning to guest immediately
+	 *   kvm:kvm_enter   means returning to vmm and then to guest
+	 */
+	return evsel__name_is(evsel, kvm_entry_trace) ||
+		evsel__name_is(evsel, kvm_reenter_trace);
+}
+
+static void event_gspr_get_key(struct evsel *evsel,
+			struct perf_sample *sample,
+			struct event_key *key)
+{
+	unsigned int insn;
+
+	key->key = LOONGARCH_EXCEPTION_OTHERS;
+	insn = evsel__intval(evsel, sample, "inst_word");
+	switch (insn >> 24) {
+	case 0:
+		/* cpucfg inst trap */
+		if ((insn >> 10) == 0x1b)
+			key->key = LOONGARCH_EXCEPTION_CPUCFG;
+		break;
+	case 4:
+		/* csr inst trap */
+		key->key = LOONGARCH_EXCEPTION_CSR;
+		break;
+	case 6:
+		/* iocsr inst trap */
+		if ((insn >> 15) == 0xc90)
+			key->key = LOONGARCH_EXCEPTION_IOCSR;
+		else if ((insn >> 15) == 0xc91)
+			/* idle inst trap */
+			key->key = LOONGARCH_EXCEPTION_IDLE;
+		break;
+	default:
+		key->key = LOONGARCH_EXCEPTION_OTHERS;
+		break;
+	}
+}
+
+static struct child_event_ops child_events[] = {
+	{ .name = "kvm:kvm_exit_gspr", .get_key = event_gspr_get_key },
+	{ NULL, NULL },
+};
+
+static struct kvm_events_ops exit_events = {
+	.is_begin_event = exit_event_begin,
+	.is_end_event = event_end,
+	.child_ops = child_events,
+	.decode_key = exit_event_decode_key,
+	.name = "VM-EXIT"
+};
+
+struct kvm_reg_events_ops kvm_reg_events_ops[] = {
+	{ .name	= "vmexit", .ops = &exit_events, },
+	{ NULL, NULL },
+};
+
+const char * const kvm_skip_events[] = {
+	NULL,
+};
+
+int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid __maybe_unused)
+{
+	kvm->exit_reasons_isa = "loongarch64";
+	kvm->exit_reasons = loongarch_exit_reasons;
+	return 0;
+}

base-commit: 2c71fdf02a95b3dd425b42f28fd47fb2b1d22702
-- 
2.39.3


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] perf kvm: Add kvm-stat for loongarch64
  2024-04-11 12:10 [PATCH v3] perf kvm: Add kvm-stat for loongarch64 Bibo Mao
@ 2024-04-19  2:34 ` maobibo
  2024-05-07  6:10 ` maobibo
  1 sibling, 0 replies; 6+ messages in thread
From: maobibo @ 2024-04-19  2:34 UTC (permalink / raw)
  To: Ming Wang, Huacai Chen
  Cc: Peter Zijlstra, Ingo Molnar, linux-kernel, linux-perf-users,
	Ian Rogers

slightly ping...

On 2024/4/11 下午8:10, Bibo Mao wrote:
> Add support for 'perf kvm stat' on loongarch64 platform, now only
> kvm exit event is supported.
> 
> Here is example output about "perf kvm --host stat report" command
> 
>     Event name   Samples   Sample%     Time (ns)   Time%   Mean Time (ns)
>      Mem store     83969    51.00%     625697070   8.00%             7451
>       Mem read     37641    22.00%     112485730   1.00%             2988
>      Interrupt     15542     9.00%      20620190   0.00%             1326
>          Iocsr     15207     9.00%      94296190   1.00%             6200
>      Hypercall      4873     2.00%      12265280   0.00%             2516
>           Idle      3713     2.00%    6322055860  87.00%          1702681
>            FPU      1819     1.00%       2750300   0.00%             1511
>         Ifecth       502     0.00%       1341740   0.00%             2672
>     Mem modify       324     0.00%        602240   0.00%             1858
>         Cpucfg        55     0.00%         77610   0.00%             1411
>            Csr        12     0.00%         19690   0.00%             1640
>           LASX         3     0.00%          4870   0.00%             1623
>            LSX         2     0.00%          2100   0.00%             1050
> 
> Signed-off-by: Bibo Mao <maobibo@loongson.cn>
> ---
> v2 --- v3:
>    1. Add NULL check with cpuid in function get_cpuid()
>    2. Add example output from /proc/cpuinfo before function get_cpuid()
> v1 --- v2:
>    1. Add child_ops for kvm exit event, split kvm:kvm_exit_gspr events
> into cpucfg/csr/iocsr/idle child events by decoding detailed gspr
> instruction.
>    2. Remove some exception code type which does not happen in current
> kvm implementation, such as meomry NR/NX/priviledge exception.
> ---
>   tools/perf/arch/loongarch/Makefile        |   1 +
>   tools/perf/arch/loongarch/util/Build      |   2 +
>   tools/perf/arch/loongarch/util/header.c   |  88 ++++++++++++++
>   tools/perf/arch/loongarch/util/kvm-stat.c | 135 ++++++++++++++++++++++
>   4 files changed, 226 insertions(+)
>   create mode 100644 tools/perf/arch/loongarch/util/header.c
>   create mode 100644 tools/perf/arch/loongarch/util/kvm-stat.c
> 
> diff --git a/tools/perf/arch/loongarch/Makefile b/tools/perf/arch/loongarch/Makefile
> index 3992a67a87d9..c89d6bb6b184 100644
> --- a/tools/perf/arch/loongarch/Makefile
> +++ b/tools/perf/arch/loongarch/Makefile
> @@ -4,6 +4,7 @@ PERF_HAVE_DWARF_REGS := 1
>   endif
>   PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
>   PERF_HAVE_JITDUMP := 1
> +HAVE_KVM_STAT_SUPPORT := 1
>   
>   #
>   # Syscall table generation for perf
> diff --git a/tools/perf/arch/loongarch/util/Build b/tools/perf/arch/loongarch/util/Build
> index d776125a2d06..b12d374d7096 100644
> --- a/tools/perf/arch/loongarch/util/Build
> +++ b/tools/perf/arch/loongarch/util/Build
> @@ -1,5 +1,7 @@
> +perf-y += header.o
>   perf-y += perf_regs.o
>   
>   perf-$(CONFIG_DWARF)     += dwarf-regs.o
>   perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
>   perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> +perf-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
> diff --git a/tools/perf/arch/loongarch/util/header.c b/tools/perf/arch/loongarch/util/header.c
> new file mode 100644
> index 000000000000..a4ed732b49c6
> --- /dev/null
> +++ b/tools/perf/arch/loongarch/util/header.c
> @@ -0,0 +1,88 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Implementation of get_cpuid().
> + *
> + * Author: Nikita Shubin <n.shubin@yadro.com>
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <api/fs/fs.h>
> +#include <errno.h>
> +#include "util/debug.h"
> +#include "util/header.h"
> +
> +/*
> + * Output example from /proc/cpuinfo
> + *   CPU Family              : Loongson-64bit
> + *   Model Name              : Loongson-3C5000
> + *   CPU Revision            : 0x11
> + */
> +#define CPUINFO_MODEL	"Model Name"
> +#define CPUINFO		"/proc/cpuinfo"
> +static char *_get_field(const char *line)
> +{
> +	char *line2, *nl;
> +
> +	line2 = strrchr(line, ' ');
> +	if (!line2)
> +		return NULL;
> +
> +	line2++;
> +	nl = strrchr(line, '\n');
> +	if (!nl)
> +		return NULL;
> +
> +	return strndup(line2, nl - line2);
> +}
> +
> +static char *__get_cpuid(void)
> +{
> +	char *line, *model, *cpuid;
> +	unsigned long line_sz;
> +	FILE *file;
> +
> +	file = fopen(CPUINFO, "r");
> +	if (file == NULL)
> +		return cpuid;
> +
> +	line = model = cpuid = NULL;
> +	while (getline(&line, &line_sz, file) != -1) {
> +		if (strncmp(line, CPUINFO_MODEL, strlen(CPUINFO_MODEL)))
> +			continue;
> +
> +		model = _get_field(line);
> +		if (!model)
> +			goto free;
> +		break;
> +	}
> +
> +	if (model && (asprintf(&cpuid, "%s", model) < 0))
> +		cpuid = NULL;
> +
> +free:
> +	fclose(file);
> +	free(model);
> +	return cpuid;
> +}
> +
> +int get_cpuid(char *buffer, size_t sz)
> +{
> +	char *cpuid = __get_cpuid();
> +	int ret = 0;
> +
> +	if (!cpuid)
> +		return EINVAL;
> +
> +	if (sz >= strlen(cpuid))
> +		scnprintf(buffer, sz, "%s", cpuid);
> +	else
> +		ret = ENOBUFS;
> +	free(cpuid);
> +	return ret;
> +}
> +
> +char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
> +{
> +	return __get_cpuid();
> +}
> diff --git a/tools/perf/arch/loongarch/util/kvm-stat.c b/tools/perf/arch/loongarch/util/kvm-stat.c
> new file mode 100644
> index 000000000000..cc50adb0835a
> --- /dev/null
> +++ b/tools/perf/arch/loongarch/util/kvm-stat.c
> @@ -0,0 +1,135 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <errno.h>
> +#include <memory.h>
> +#include <errno.h>
> +#include "util/kvm-stat.h"
> +#include "util/parse-events.h"
> +#include "util/debug.h"
> +#include "util/evsel.h"
> +#include "util/evlist.h"
> +#include "util/pmus.h"
> +
> +#define LOONGARCH_EXCEPTION_INT		0
> +#define LOONGARCH_EXCEPTION_PIL		1
> +#define LOONGARCH_EXCEPTION_PIS		2
> +#define LOONGARCH_EXCEPTION_PIF		3
> +#define LOONGARCH_EXCEPTION_PME		4
> +#define LOONGARCH_EXCEPTION_FPD		15
> +#define LOONGARCH_EXCEPTION_SXD		16
> +#define LOONGARCH_EXCEPTION_ASXD	17
> +#define LOONGARCH_EXCEPTION_GSPR	22
> +#define  LOONGARCH_EXCEPTION_CPUCFG	100
> +#define  LOONGARCH_EXCEPTION_CSR	101
> +#define  LOONGARCH_EXCEPTION_IOCSR	102
> +#define  LOONGARCH_EXCEPTION_IDLE	103
> +#define  LOONGARCH_EXCEPTION_OTHERS	104
> +#define LOONGARCH_EXCEPTION_HVC		23
> +
> +#define loongarch_exception_type				\
> +	{LOONGARCH_EXCEPTION_INT,  "Interrupt" },		\
> +	{LOONGARCH_EXCEPTION_PIL,  "Mem read" },		\
> +	{LOONGARCH_EXCEPTION_PIS,  "Mem store" },		\
> +	{LOONGARCH_EXCEPTION_PIF,  "Ifecth" },			\
> +	{LOONGARCH_EXCEPTION_PME,  "Mem modify" },		\
> +	{LOONGARCH_EXCEPTION_FPD,  "FPU" },			\
> +	{LOONGARCH_EXCEPTION_SXD,  "LSX" },			\
> +	{LOONGARCH_EXCEPTION_ASXD, "LASX" },			\
> +	{LOONGARCH_EXCEPTION_GSPR, "Privilege Error" },		\
> +	{LOONGARCH_EXCEPTION_HVC,  "Hypercall" },		\
> +	{LOONGARCH_EXCEPTION_CPUCFG, "Cpucfg" },		\
> +	{LOONGARCH_EXCEPTION_CSR,    "Csr" },			\
> +	{LOONGARCH_EXCEPTION_IOCSR,  "Iocsr" },			\
> +	{LOONGARCH_EXCEPTION_IDLE,   "Idle" },			\
> +	{LOONGARCH_EXCEPTION_OTHERS, "Others" }
> +
> +define_exit_reasons_table(loongarch_exit_reasons, loongarch_exception_type);
> +
> +const char *vcpu_id_str = "vcpu_id";
> +const char *kvm_exit_reason = "reason";
> +const char *kvm_entry_trace = "kvm:kvm_enter";
> +const char *kvm_reenter_trace = "kvm:kvm_reenter";
> +const char *kvm_exit_trace = "kvm:kvm_exit";
> +const char *kvm_events_tp[] = {
> +	"kvm:kvm_enter",
> +	"kvm:kvm_reenter",
> +	"kvm:kvm_exit",
> +	"kvm:kvm_exit_gspr",
> +	NULL,
> +};
> +
> +static bool event_end(struct evsel *evsel,
> +		struct perf_sample *sample __maybe_unused,
> +		struct event_key *key __maybe_unused)
> +{
> +	/*
> +	 * LoongArch kvm is different with other architectures
> +	 *
> +	 * There is kvm:kvm_reenter or kvm:kvm_enter event adjacent with
> +	 * kvm:kvm_exit event.
> +	 *   kvm:kvm_reenter means returning to guest immediately
> +	 *   kvm:kvm_enter   means returning to vmm and then to guest
> +	 */
> +	return evsel__name_is(evsel, kvm_entry_trace) ||
> +		evsel__name_is(evsel, kvm_reenter_trace);
> +}
> +
> +static void event_gspr_get_key(struct evsel *evsel,
> +			struct perf_sample *sample,
> +			struct event_key *key)
> +{
> +	unsigned int insn;
> +
> +	key->key = LOONGARCH_EXCEPTION_OTHERS;
> +	insn = evsel__intval(evsel, sample, "inst_word");
> +	switch (insn >> 24) {
> +	case 0:
> +		/* cpucfg inst trap */
> +		if ((insn >> 10) == 0x1b)
> +			key->key = LOONGARCH_EXCEPTION_CPUCFG;
> +		break;
> +	case 4:
> +		/* csr inst trap */
> +		key->key = LOONGARCH_EXCEPTION_CSR;
> +		break;
> +	case 6:
> +		/* iocsr inst trap */
> +		if ((insn >> 15) == 0xc90)
> +			key->key = LOONGARCH_EXCEPTION_IOCSR;
> +		else if ((insn >> 15) == 0xc91)
> +			/* idle inst trap */
> +			key->key = LOONGARCH_EXCEPTION_IDLE;
> +		break;
> +	default:
> +		key->key = LOONGARCH_EXCEPTION_OTHERS;
> +		break;
> +	}
> +}
> +
> +static struct child_event_ops child_events[] = {
> +	{ .name = "kvm:kvm_exit_gspr", .get_key = event_gspr_get_key },
> +	{ NULL, NULL },
> +};
> +
> +static struct kvm_events_ops exit_events = {
> +	.is_begin_event = exit_event_begin,
> +	.is_end_event = event_end,
> +	.child_ops = child_events,
> +	.decode_key = exit_event_decode_key,
> +	.name = "VM-EXIT"
> +};
> +
> +struct kvm_reg_events_ops kvm_reg_events_ops[] = {
> +	{ .name	= "vmexit", .ops = &exit_events, },
> +	{ NULL, NULL },
> +};
> +
> +const char * const kvm_skip_events[] = {
> +	NULL,
> +};
> +
> +int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid __maybe_unused)
> +{
> +	kvm->exit_reasons_isa = "loongarch64";
> +	kvm->exit_reasons = loongarch_exit_reasons;
> +	return 0;
> +}
> 
> base-commit: 2c71fdf02a95b3dd425b42f28fd47fb2b1d22702
> 


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] perf kvm: Add kvm-stat for loongarch64
  2024-04-11 12:10 [PATCH v3] perf kvm: Add kvm-stat for loongarch64 Bibo Mao
  2024-04-19  2:34 ` maobibo
@ 2024-05-07  6:10 ` maobibo
  2024-05-08 13:02   ` Huacai Chen
  1 sibling, 1 reply; 6+ messages in thread
From: maobibo @ 2024-05-07  6:10 UTC (permalink / raw)
  To: Huacai Chen, Peter Zijlstra, Ian Rogers
  Cc: Ming Wang, Ingo Molnar, linux-kernel, linux-perf-users

Hi Peter/Ian/Huacai,

This patch stays one month without response, I know you are busy and 
look through thousands of patch every day.

Just one question, who has permission to merge perf kvm patch for 
LoongArch. Is it LoongArch maintainer or perf kvm maintainer?

Regards
Bibo Mao


On 2024/4/11 下午8:10, Bibo Mao wrote:
> Add support for 'perf kvm stat' on loongarch64 platform, now only
> kvm exit event is supported.
> 
> Here is example output about "perf kvm --host stat report" command
> 
>     Event name   Samples   Sample%     Time (ns)   Time%   Mean Time (ns)
>      Mem store     83969    51.00%     625697070   8.00%             7451
>       Mem read     37641    22.00%     112485730   1.00%             2988
>      Interrupt     15542     9.00%      20620190   0.00%             1326
>          Iocsr     15207     9.00%      94296190   1.00%             6200
>      Hypercall      4873     2.00%      12265280   0.00%             2516
>           Idle      3713     2.00%    6322055860  87.00%          1702681
>            FPU      1819     1.00%       2750300   0.00%             1511
>         Ifecth       502     0.00%       1341740   0.00%             2672
>     Mem modify       324     0.00%        602240   0.00%             1858
>         Cpucfg        55     0.00%         77610   0.00%             1411
>            Csr        12     0.00%         19690   0.00%             1640
>           LASX         3     0.00%          4870   0.00%             1623
>            LSX         2     0.00%          2100   0.00%             1050
> 
> Signed-off-by: Bibo Mao <maobibo@loongson.cn>
> ---
> v2 --- v3:
>    1. Add NULL check with cpuid in function get_cpuid()
>    2. Add example output from /proc/cpuinfo before function get_cpuid()
> v1 --- v2:
>    1. Add child_ops for kvm exit event, split kvm:kvm_exit_gspr events
> into cpucfg/csr/iocsr/idle child events by decoding detailed gspr
> instruction.
>    2. Remove some exception code type which does not happen in current
> kvm implementation, such as meomry NR/NX/priviledge exception.
> ---
>   tools/perf/arch/loongarch/Makefile        |   1 +
>   tools/perf/arch/loongarch/util/Build      |   2 +
>   tools/perf/arch/loongarch/util/header.c   |  88 ++++++++++++++
>   tools/perf/arch/loongarch/util/kvm-stat.c | 135 ++++++++++++++++++++++
>   4 files changed, 226 insertions(+)
>   create mode 100644 tools/perf/arch/loongarch/util/header.c
>   create mode 100644 tools/perf/arch/loongarch/util/kvm-stat.c
> 
> diff --git a/tools/perf/arch/loongarch/Makefile b/tools/perf/arch/loongarch/Makefile
> index 3992a67a87d9..c89d6bb6b184 100644
> --- a/tools/perf/arch/loongarch/Makefile
> +++ b/tools/perf/arch/loongarch/Makefile
> @@ -4,6 +4,7 @@ PERF_HAVE_DWARF_REGS := 1
>   endif
>   PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
>   PERF_HAVE_JITDUMP := 1
> +HAVE_KVM_STAT_SUPPORT := 1
>   
>   #
>   # Syscall table generation for perf
> diff --git a/tools/perf/arch/loongarch/util/Build b/tools/perf/arch/loongarch/util/Build
> index d776125a2d06..b12d374d7096 100644
> --- a/tools/perf/arch/loongarch/util/Build
> +++ b/tools/perf/arch/loongarch/util/Build
> @@ -1,5 +1,7 @@
> +perf-y += header.o
>   perf-y += perf_regs.o
>   
>   perf-$(CONFIG_DWARF)     += dwarf-regs.o
>   perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
>   perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> +perf-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
> diff --git a/tools/perf/arch/loongarch/util/header.c b/tools/perf/arch/loongarch/util/header.c
> new file mode 100644
> index 000000000000..a4ed732b49c6
> --- /dev/null
> +++ b/tools/perf/arch/loongarch/util/header.c
> @@ -0,0 +1,88 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Implementation of get_cpuid().
> + *
> + * Author: Nikita Shubin <n.shubin@yadro.com>
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <api/fs/fs.h>
> +#include <errno.h>
> +#include "util/debug.h"
> +#include "util/header.h"
> +
> +/*
> + * Output example from /proc/cpuinfo
> + *   CPU Family              : Loongson-64bit
> + *   Model Name              : Loongson-3C5000
> + *   CPU Revision            : 0x11
> + */
> +#define CPUINFO_MODEL	"Model Name"
> +#define CPUINFO		"/proc/cpuinfo"
> +static char *_get_field(const char *line)
> +{
> +	char *line2, *nl;
> +
> +	line2 = strrchr(line, ' ');
> +	if (!line2)
> +		return NULL;
> +
> +	line2++;
> +	nl = strrchr(line, '\n');
> +	if (!nl)
> +		return NULL;
> +
> +	return strndup(line2, nl - line2);
> +}
> +
> +static char *__get_cpuid(void)
> +{
> +	char *line, *model, *cpuid;
> +	unsigned long line_sz;
> +	FILE *file;
> +
> +	file = fopen(CPUINFO, "r");
> +	if (file == NULL)
> +		return cpuid;
> +
> +	line = model = cpuid = NULL;
> +	while (getline(&line, &line_sz, file) != -1) {
> +		if (strncmp(line, CPUINFO_MODEL, strlen(CPUINFO_MODEL)))
> +			continue;
> +
> +		model = _get_field(line);
> +		if (!model)
> +			goto free;
> +		break;
> +	}
> +
> +	if (model && (asprintf(&cpuid, "%s", model) < 0))
> +		cpuid = NULL;
> +
> +free:
> +	fclose(file);
> +	free(model);
> +	return cpuid;
> +}
> +
> +int get_cpuid(char *buffer, size_t sz)
> +{
> +	char *cpuid = __get_cpuid();
> +	int ret = 0;
> +
> +	if (!cpuid)
> +		return EINVAL;
> +
> +	if (sz >= strlen(cpuid))
> +		scnprintf(buffer, sz, "%s", cpuid);
> +	else
> +		ret = ENOBUFS;
> +	free(cpuid);
> +	return ret;
> +}
> +
> +char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
> +{
> +	return __get_cpuid();
> +}
> diff --git a/tools/perf/arch/loongarch/util/kvm-stat.c b/tools/perf/arch/loongarch/util/kvm-stat.c
> new file mode 100644
> index 000000000000..cc50adb0835a
> --- /dev/null
> +++ b/tools/perf/arch/loongarch/util/kvm-stat.c
> @@ -0,0 +1,135 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <errno.h>
> +#include <memory.h>
> +#include <errno.h>
> +#include "util/kvm-stat.h"
> +#include "util/parse-events.h"
> +#include "util/debug.h"
> +#include "util/evsel.h"
> +#include "util/evlist.h"
> +#include "util/pmus.h"
> +
> +#define LOONGARCH_EXCEPTION_INT		0
> +#define LOONGARCH_EXCEPTION_PIL		1
> +#define LOONGARCH_EXCEPTION_PIS		2
> +#define LOONGARCH_EXCEPTION_PIF		3
> +#define LOONGARCH_EXCEPTION_PME		4
> +#define LOONGARCH_EXCEPTION_FPD		15
> +#define LOONGARCH_EXCEPTION_SXD		16
> +#define LOONGARCH_EXCEPTION_ASXD	17
> +#define LOONGARCH_EXCEPTION_GSPR	22
> +#define  LOONGARCH_EXCEPTION_CPUCFG	100
> +#define  LOONGARCH_EXCEPTION_CSR	101
> +#define  LOONGARCH_EXCEPTION_IOCSR	102
> +#define  LOONGARCH_EXCEPTION_IDLE	103
> +#define  LOONGARCH_EXCEPTION_OTHERS	104
> +#define LOONGARCH_EXCEPTION_HVC		23
> +
> +#define loongarch_exception_type				\
> +	{LOONGARCH_EXCEPTION_INT,  "Interrupt" },		\
> +	{LOONGARCH_EXCEPTION_PIL,  "Mem read" },		\
> +	{LOONGARCH_EXCEPTION_PIS,  "Mem store" },		\
> +	{LOONGARCH_EXCEPTION_PIF,  "Ifecth" },			\
> +	{LOONGARCH_EXCEPTION_PME,  "Mem modify" },		\
> +	{LOONGARCH_EXCEPTION_FPD,  "FPU" },			\
> +	{LOONGARCH_EXCEPTION_SXD,  "LSX" },			\
> +	{LOONGARCH_EXCEPTION_ASXD, "LASX" },			\
> +	{LOONGARCH_EXCEPTION_GSPR, "Privilege Error" },		\
> +	{LOONGARCH_EXCEPTION_HVC,  "Hypercall" },		\
> +	{LOONGARCH_EXCEPTION_CPUCFG, "Cpucfg" },		\
> +	{LOONGARCH_EXCEPTION_CSR,    "Csr" },			\
> +	{LOONGARCH_EXCEPTION_IOCSR,  "Iocsr" },			\
> +	{LOONGARCH_EXCEPTION_IDLE,   "Idle" },			\
> +	{LOONGARCH_EXCEPTION_OTHERS, "Others" }
> +
> +define_exit_reasons_table(loongarch_exit_reasons, loongarch_exception_type);
> +
> +const char *vcpu_id_str = "vcpu_id";
> +const char *kvm_exit_reason = "reason";
> +const char *kvm_entry_trace = "kvm:kvm_enter";
> +const char *kvm_reenter_trace = "kvm:kvm_reenter";
> +const char *kvm_exit_trace = "kvm:kvm_exit";
> +const char *kvm_events_tp[] = {
> +	"kvm:kvm_enter",
> +	"kvm:kvm_reenter",
> +	"kvm:kvm_exit",
> +	"kvm:kvm_exit_gspr",
> +	NULL,
> +};
> +
> +static bool event_end(struct evsel *evsel,
> +		struct perf_sample *sample __maybe_unused,
> +		struct event_key *key __maybe_unused)
> +{
> +	/*
> +	 * LoongArch kvm is different with other architectures
> +	 *
> +	 * There is kvm:kvm_reenter or kvm:kvm_enter event adjacent with
> +	 * kvm:kvm_exit event.
> +	 *   kvm:kvm_reenter means returning to guest immediately
> +	 *   kvm:kvm_enter   means returning to vmm and then to guest
> +	 */
> +	return evsel__name_is(evsel, kvm_entry_trace) ||
> +		evsel__name_is(evsel, kvm_reenter_trace);
> +}
> +
> +static void event_gspr_get_key(struct evsel *evsel,
> +			struct perf_sample *sample,
> +			struct event_key *key)
> +{
> +	unsigned int insn;
> +
> +	key->key = LOONGARCH_EXCEPTION_OTHERS;
> +	insn = evsel__intval(evsel, sample, "inst_word");
> +	switch (insn >> 24) {
> +	case 0:
> +		/* cpucfg inst trap */
> +		if ((insn >> 10) == 0x1b)
> +			key->key = LOONGARCH_EXCEPTION_CPUCFG;
> +		break;
> +	case 4:
> +		/* csr inst trap */
> +		key->key = LOONGARCH_EXCEPTION_CSR;
> +		break;
> +	case 6:
> +		/* iocsr inst trap */
> +		if ((insn >> 15) == 0xc90)
> +			key->key = LOONGARCH_EXCEPTION_IOCSR;
> +		else if ((insn >> 15) == 0xc91)
> +			/* idle inst trap */
> +			key->key = LOONGARCH_EXCEPTION_IDLE;
> +		break;
> +	default:
> +		key->key = LOONGARCH_EXCEPTION_OTHERS;
> +		break;
> +	}
> +}
> +
> +static struct child_event_ops child_events[] = {
> +	{ .name = "kvm:kvm_exit_gspr", .get_key = event_gspr_get_key },
> +	{ NULL, NULL },
> +};
> +
> +static struct kvm_events_ops exit_events = {
> +	.is_begin_event = exit_event_begin,
> +	.is_end_event = event_end,
> +	.child_ops = child_events,
> +	.decode_key = exit_event_decode_key,
> +	.name = "VM-EXIT"
> +};
> +
> +struct kvm_reg_events_ops kvm_reg_events_ops[] = {
> +	{ .name	= "vmexit", .ops = &exit_events, },
> +	{ NULL, NULL },
> +};
> +
> +const char * const kvm_skip_events[] = {
> +	NULL,
> +};
> +
> +int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid __maybe_unused)
> +{
> +	kvm->exit_reasons_isa = "loongarch64";
> +	kvm->exit_reasons = loongarch_exit_reasons;
> +	return 0;
> +}
> 
> base-commit: 2c71fdf02a95b3dd425b42f28fd47fb2b1d22702
> 


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] perf kvm: Add kvm-stat for loongarch64
  2024-05-07  6:10 ` maobibo
@ 2024-05-08 13:02   ` Huacai Chen
  2024-05-10  1:47     ` maobibo
  0 siblings, 1 reply; 6+ messages in thread
From: Huacai Chen @ 2024-05-08 13:02 UTC (permalink / raw)
  To: maobibo
  Cc: Peter Zijlstra, Ian Rogers, Ming Wang, Ingo Molnar, linux-kernel,
	linux-perf-users

On Tue, May 7, 2024 at 2:11 PM maobibo <maobibo@loongson.cn> wrote:
>
> Hi Peter/Ian/Huacai,
>
> This patch stays one month without response, I know you are busy and
> look through thousands of patch every day.
>
> Just one question, who has permission to merge perf kvm patch for
> LoongArch. Is it LoongArch maintainer or perf kvm maintainer?
It should probably go to perf tree, but if it is allowed, maybe I can
try to merge into LoongArch tree.


Huacai
>
> Regards
> Bibo Mao
>
>
> On 2024/4/11 下午8:10, Bibo Mao wrote:
> > Add support for 'perf kvm stat' on loongarch64 platform, now only
> > kvm exit event is supported.
> >
> > Here is example output about "perf kvm --host stat report" command
> >
> >     Event name   Samples   Sample%     Time (ns)   Time%   Mean Time (ns)
> >      Mem store     83969    51.00%     625697070   8.00%             7451
> >       Mem read     37641    22.00%     112485730   1.00%             2988
> >      Interrupt     15542     9.00%      20620190   0.00%             1326
> >          Iocsr     15207     9.00%      94296190   1.00%             6200
> >      Hypercall      4873     2.00%      12265280   0.00%             2516
> >           Idle      3713     2.00%    6322055860  87.00%          1702681
> >            FPU      1819     1.00%       2750300   0.00%             1511
> >         Ifecth       502     0.00%       1341740   0.00%             2672
> >     Mem modify       324     0.00%        602240   0.00%             1858
> >         Cpucfg        55     0.00%         77610   0.00%             1411
> >            Csr        12     0.00%         19690   0.00%             1640
> >           LASX         3     0.00%          4870   0.00%             1623
> >            LSX         2     0.00%          2100   0.00%             1050
> >
> > Signed-off-by: Bibo Mao <maobibo@loongson.cn>
> > ---
> > v2 --- v3:
> >    1. Add NULL check with cpuid in function get_cpuid()
> >    2. Add example output from /proc/cpuinfo before function get_cpuid()
> > v1 --- v2:
> >    1. Add child_ops for kvm exit event, split kvm:kvm_exit_gspr events
> > into cpucfg/csr/iocsr/idle child events by decoding detailed gspr
> > instruction.
> >    2. Remove some exception code type which does not happen in current
> > kvm implementation, such as meomry NR/NX/priviledge exception.
> > ---
> >   tools/perf/arch/loongarch/Makefile        |   1 +
> >   tools/perf/arch/loongarch/util/Build      |   2 +
> >   tools/perf/arch/loongarch/util/header.c   |  88 ++++++++++++++
> >   tools/perf/arch/loongarch/util/kvm-stat.c | 135 ++++++++++++++++++++++
> >   4 files changed, 226 insertions(+)
> >   create mode 100644 tools/perf/arch/loongarch/util/header.c
> >   create mode 100644 tools/perf/arch/loongarch/util/kvm-stat.c
> >
> > diff --git a/tools/perf/arch/loongarch/Makefile b/tools/perf/arch/loongarch/Makefile
> > index 3992a67a87d9..c89d6bb6b184 100644
> > --- a/tools/perf/arch/loongarch/Makefile
> > +++ b/tools/perf/arch/loongarch/Makefile
> > @@ -4,6 +4,7 @@ PERF_HAVE_DWARF_REGS := 1
> >   endif
> >   PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
> >   PERF_HAVE_JITDUMP := 1
> > +HAVE_KVM_STAT_SUPPORT := 1
> >
> >   #
> >   # Syscall table generation for perf
> > diff --git a/tools/perf/arch/loongarch/util/Build b/tools/perf/arch/loongarch/util/Build
> > index d776125a2d06..b12d374d7096 100644
> > --- a/tools/perf/arch/loongarch/util/Build
> > +++ b/tools/perf/arch/loongarch/util/Build
> > @@ -1,5 +1,7 @@
> > +perf-y += header.o
> >   perf-y += perf_regs.o
> >
> >   perf-$(CONFIG_DWARF)     += dwarf-regs.o
> >   perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
> >   perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> > +perf-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
> > diff --git a/tools/perf/arch/loongarch/util/header.c b/tools/perf/arch/loongarch/util/header.c
> > new file mode 100644
> > index 000000000000..a4ed732b49c6
> > --- /dev/null
> > +++ b/tools/perf/arch/loongarch/util/header.c
> > @@ -0,0 +1,88 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Implementation of get_cpuid().
> > + *
> > + * Author: Nikita Shubin <n.shubin@yadro.com>
> > + */
> > +
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <api/fs/fs.h>
> > +#include <errno.h>
> > +#include "util/debug.h"
> > +#include "util/header.h"
> > +
> > +/*
> > + * Output example from /proc/cpuinfo
> > + *   CPU Family              : Loongson-64bit
> > + *   Model Name              : Loongson-3C5000
> > + *   CPU Revision            : 0x11
> > + */
> > +#define CPUINFO_MODEL        "Model Name"
> > +#define CPUINFO              "/proc/cpuinfo"
> > +static char *_get_field(const char *line)
> > +{
> > +     char *line2, *nl;
> > +
> > +     line2 = strrchr(line, ' ');
> > +     if (!line2)
> > +             return NULL;
> > +
> > +     line2++;
> > +     nl = strrchr(line, '\n');
> > +     if (!nl)
> > +             return NULL;
> > +
> > +     return strndup(line2, nl - line2);
> > +}
> > +
> > +static char *__get_cpuid(void)
> > +{
> > +     char *line, *model, *cpuid;
> > +     unsigned long line_sz;
> > +     FILE *file;
> > +
> > +     file = fopen(CPUINFO, "r");
> > +     if (file == NULL)
> > +             return cpuid;
> > +
> > +     line = model = cpuid = NULL;
> > +     while (getline(&line, &line_sz, file) != -1) {
> > +             if (strncmp(line, CPUINFO_MODEL, strlen(CPUINFO_MODEL)))
> > +                     continue;
> > +
> > +             model = _get_field(line);
> > +             if (!model)
> > +                     goto free;
> > +             break;
> > +     }
> > +
> > +     if (model && (asprintf(&cpuid, "%s", model) < 0))
> > +             cpuid = NULL;
> > +
> > +free:
> > +     fclose(file);
> > +     free(model);
> > +     return cpuid;
> > +}
> > +
> > +int get_cpuid(char *buffer, size_t sz)
> > +{
> > +     char *cpuid = __get_cpuid();
> > +     int ret = 0;
> > +
> > +     if (!cpuid)
> > +             return EINVAL;
> > +
> > +     if (sz >= strlen(cpuid))
> > +             scnprintf(buffer, sz, "%s", cpuid);
> > +     else
> > +             ret = ENOBUFS;
> > +     free(cpuid);
> > +     return ret;
> > +}
> > +
> > +char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
> > +{
> > +     return __get_cpuid();
> > +}
> > diff --git a/tools/perf/arch/loongarch/util/kvm-stat.c b/tools/perf/arch/loongarch/util/kvm-stat.c
> > new file mode 100644
> > index 000000000000..cc50adb0835a
> > --- /dev/null
> > +++ b/tools/perf/arch/loongarch/util/kvm-stat.c
> > @@ -0,0 +1,135 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +#include <errno.h>
> > +#include <memory.h>
> > +#include <errno.h>
> > +#include "util/kvm-stat.h"
> > +#include "util/parse-events.h"
> > +#include "util/debug.h"
> > +#include "util/evsel.h"
> > +#include "util/evlist.h"
> > +#include "util/pmus.h"
> > +
> > +#define LOONGARCH_EXCEPTION_INT              0
> > +#define LOONGARCH_EXCEPTION_PIL              1
> > +#define LOONGARCH_EXCEPTION_PIS              2
> > +#define LOONGARCH_EXCEPTION_PIF              3
> > +#define LOONGARCH_EXCEPTION_PME              4
> > +#define LOONGARCH_EXCEPTION_FPD              15
> > +#define LOONGARCH_EXCEPTION_SXD              16
> > +#define LOONGARCH_EXCEPTION_ASXD     17
> > +#define LOONGARCH_EXCEPTION_GSPR     22
> > +#define  LOONGARCH_EXCEPTION_CPUCFG  100
> > +#define  LOONGARCH_EXCEPTION_CSR     101
> > +#define  LOONGARCH_EXCEPTION_IOCSR   102
> > +#define  LOONGARCH_EXCEPTION_IDLE    103
> > +#define  LOONGARCH_EXCEPTION_OTHERS  104
> > +#define LOONGARCH_EXCEPTION_HVC              23
> > +
> > +#define loongarch_exception_type                             \
> > +     {LOONGARCH_EXCEPTION_INT,  "Interrupt" },               \
> > +     {LOONGARCH_EXCEPTION_PIL,  "Mem read" },                \
> > +     {LOONGARCH_EXCEPTION_PIS,  "Mem store" },               \
> > +     {LOONGARCH_EXCEPTION_PIF,  "Ifecth" },                  \
> > +     {LOONGARCH_EXCEPTION_PME,  "Mem modify" },              \
> > +     {LOONGARCH_EXCEPTION_FPD,  "FPU" },                     \
> > +     {LOONGARCH_EXCEPTION_SXD,  "LSX" },                     \
> > +     {LOONGARCH_EXCEPTION_ASXD, "LASX" },                    \
> > +     {LOONGARCH_EXCEPTION_GSPR, "Privilege Error" },         \
> > +     {LOONGARCH_EXCEPTION_HVC,  "Hypercall" },               \
> > +     {LOONGARCH_EXCEPTION_CPUCFG, "Cpucfg" },                \
> > +     {LOONGARCH_EXCEPTION_CSR,    "Csr" },                   \
> > +     {LOONGARCH_EXCEPTION_IOCSR,  "Iocsr" },                 \
> > +     {LOONGARCH_EXCEPTION_IDLE,   "Idle" },                  \
> > +     {LOONGARCH_EXCEPTION_OTHERS, "Others" }
> > +
> > +define_exit_reasons_table(loongarch_exit_reasons, loongarch_exception_type);
> > +
> > +const char *vcpu_id_str = "vcpu_id";
> > +const char *kvm_exit_reason = "reason";
> > +const char *kvm_entry_trace = "kvm:kvm_enter";
> > +const char *kvm_reenter_trace = "kvm:kvm_reenter";
> > +const char *kvm_exit_trace = "kvm:kvm_exit";
> > +const char *kvm_events_tp[] = {
> > +     "kvm:kvm_enter",
> > +     "kvm:kvm_reenter",
> > +     "kvm:kvm_exit",
> > +     "kvm:kvm_exit_gspr",
> > +     NULL,
> > +};
> > +
> > +static bool event_end(struct evsel *evsel,
> > +             struct perf_sample *sample __maybe_unused,
> > +             struct event_key *key __maybe_unused)
> > +{
> > +     /*
> > +      * LoongArch kvm is different with other architectures
> > +      *
> > +      * There is kvm:kvm_reenter or kvm:kvm_enter event adjacent with
> > +      * kvm:kvm_exit event.
> > +      *   kvm:kvm_reenter means returning to guest immediately
> > +      *   kvm:kvm_enter   means returning to vmm and then to guest
> > +      */
> > +     return evsel__name_is(evsel, kvm_entry_trace) ||
> > +             evsel__name_is(evsel, kvm_reenter_trace);
> > +}
> > +
> > +static void event_gspr_get_key(struct evsel *evsel,
> > +                     struct perf_sample *sample,
> > +                     struct event_key *key)
> > +{
> > +     unsigned int insn;
> > +
> > +     key->key = LOONGARCH_EXCEPTION_OTHERS;
> > +     insn = evsel__intval(evsel, sample, "inst_word");
> > +     switch (insn >> 24) {
> > +     case 0:
> > +             /* cpucfg inst trap */
> > +             if ((insn >> 10) == 0x1b)
> > +                     key->key = LOONGARCH_EXCEPTION_CPUCFG;
> > +             break;
> > +     case 4:
> > +             /* csr inst trap */
> > +             key->key = LOONGARCH_EXCEPTION_CSR;
> > +             break;
> > +     case 6:
> > +             /* iocsr inst trap */
> > +             if ((insn >> 15) == 0xc90)
> > +                     key->key = LOONGARCH_EXCEPTION_IOCSR;
> > +             else if ((insn >> 15) == 0xc91)
> > +                     /* idle inst trap */
> > +                     key->key = LOONGARCH_EXCEPTION_IDLE;
> > +             break;
> > +     default:
> > +             key->key = LOONGARCH_EXCEPTION_OTHERS;
> > +             break;
> > +     }
> > +}
> > +
> > +static struct child_event_ops child_events[] = {
> > +     { .name = "kvm:kvm_exit_gspr", .get_key = event_gspr_get_key },
> > +     { NULL, NULL },
> > +};
> > +
> > +static struct kvm_events_ops exit_events = {
> > +     .is_begin_event = exit_event_begin,
> > +     .is_end_event = event_end,
> > +     .child_ops = child_events,
> > +     .decode_key = exit_event_decode_key,
> > +     .name = "VM-EXIT"
> > +};
> > +
> > +struct kvm_reg_events_ops kvm_reg_events_ops[] = {
> > +     { .name = "vmexit", .ops = &exit_events, },
> > +     { NULL, NULL },
> > +};
> > +
> > +const char * const kvm_skip_events[] = {
> > +     NULL,
> > +};
> > +
> > +int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid __maybe_unused)
> > +{
> > +     kvm->exit_reasons_isa = "loongarch64";
> > +     kvm->exit_reasons = loongarch_exit_reasons;
> > +     return 0;
> > +}
> >
> > base-commit: 2c71fdf02a95b3dd425b42f28fd47fb2b1d22702
> >
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] perf kvm: Add kvm-stat for loongarch64
  2024-05-08 13:02   ` Huacai Chen
@ 2024-05-10  1:47     ` maobibo
  2024-07-05  9:38       ` Huacai Chen
  0 siblings, 1 reply; 6+ messages in thread
From: maobibo @ 2024-05-10  1:47 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Peter Zijlstra, Ian Rogers, Ming Wang, Ingo Molnar, linux-kernel,
	linux-perf-users



On 2024/5/8 下午9:02, Huacai Chen wrote:
> On Tue, May 7, 2024 at 2:11 PM maobibo <maobibo@loongson.cn> wrote:
>>
>> Hi Peter/Ian/Huacai,
>>
>> This patch stays one month without response, I know you are busy and
>> look through thousands of patch every day.
>>
>> Just one question, who has permission to merge perf kvm patch for
>> LoongArch. Is it LoongArch maintainer or perf kvm maintainer?
> It should probably go to perf tree, but if it is allowed, maybe I can
> try to merge into LoongArch tree.

  tools/perf/arch/loongarch/Makefile        |   1 +
  tools/perf/arch/loongarch/util/Build      |   2 +
  tools/perf/arch/loongarch/util/header.c   |  88 ++++++++++++++
  tools/perf/arch/loongarch/util/kvm-stat.c | 135 ++++++++++++++++++++++

All the modification is LoongArch specific, there will be much 
appreciated if it can reviewed and merged.

Regards
Bibo Mao

> 
> 
> Huacai
>>
>> Regards
>> Bibo Mao
>>
>>
>> On 2024/4/11 下午8:10, Bibo Mao wrote:
>>> Add support for 'perf kvm stat' on loongarch64 platform, now only
>>> kvm exit event is supported.
>>>
>>> Here is example output about "perf kvm --host stat report" command
>>>
>>>      Event name   Samples   Sample%     Time (ns)   Time%   Mean Time (ns)
>>>       Mem store     83969    51.00%     625697070   8.00%             7451
>>>        Mem read     37641    22.00%     112485730   1.00%             2988
>>>       Interrupt     15542     9.00%      20620190   0.00%             1326
>>>           Iocsr     15207     9.00%      94296190   1.00%             6200
>>>       Hypercall      4873     2.00%      12265280   0.00%             2516
>>>            Idle      3713     2.00%    6322055860  87.00%          1702681
>>>             FPU      1819     1.00%       2750300   0.00%             1511
>>>          Ifecth       502     0.00%       1341740   0.00%             2672
>>>      Mem modify       324     0.00%        602240   0.00%             1858
>>>          Cpucfg        55     0.00%         77610   0.00%             1411
>>>             Csr        12     0.00%         19690   0.00%             1640
>>>            LASX         3     0.00%          4870   0.00%             1623
>>>             LSX         2     0.00%          2100   0.00%             1050
>>>
>>> Signed-off-by: Bibo Mao <maobibo@loongson.cn>
>>> ---
>>> v2 --- v3:
>>>     1. Add NULL check with cpuid in function get_cpuid()
>>>     2. Add example output from /proc/cpuinfo before function get_cpuid()
>>> v1 --- v2:
>>>     1. Add child_ops for kvm exit event, split kvm:kvm_exit_gspr events
>>> into cpucfg/csr/iocsr/idle child events by decoding detailed gspr
>>> instruction.
>>>     2. Remove some exception code type which does not happen in current
>>> kvm implementation, such as meomry NR/NX/priviledge exception.
>>> ---
>>>    tools/perf/arch/loongarch/Makefile        |   1 +
>>>    tools/perf/arch/loongarch/util/Build      |   2 +
>>>    tools/perf/arch/loongarch/util/header.c   |  88 ++++++++++++++
>>>    tools/perf/arch/loongarch/util/kvm-stat.c | 135 ++++++++++++++++++++++
>>>    4 files changed, 226 insertions(+)
>>>    create mode 100644 tools/perf/arch/loongarch/util/header.c
>>>    create mode 100644 tools/perf/arch/loongarch/util/kvm-stat.c
>>>
>>> diff --git a/tools/perf/arch/loongarch/Makefile b/tools/perf/arch/loongarch/Makefile
>>> index 3992a67a87d9..c89d6bb6b184 100644
>>> --- a/tools/perf/arch/loongarch/Makefile
>>> +++ b/tools/perf/arch/loongarch/Makefile
>>> @@ -4,6 +4,7 @@ PERF_HAVE_DWARF_REGS := 1
>>>    endif
>>>    PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
>>>    PERF_HAVE_JITDUMP := 1
>>> +HAVE_KVM_STAT_SUPPORT := 1
>>>
>>>    #
>>>    # Syscall table generation for perf
>>> diff --git a/tools/perf/arch/loongarch/util/Build b/tools/perf/arch/loongarch/util/Build
>>> index d776125a2d06..b12d374d7096 100644
>>> --- a/tools/perf/arch/loongarch/util/Build
>>> +++ b/tools/perf/arch/loongarch/util/Build
>>> @@ -1,5 +1,7 @@
>>> +perf-y += header.o
>>>    perf-y += perf_regs.o
>>>
>>>    perf-$(CONFIG_DWARF)     += dwarf-regs.o
>>>    perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
>>>    perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
>>> +perf-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
>>> diff --git a/tools/perf/arch/loongarch/util/header.c b/tools/perf/arch/loongarch/util/header.c
>>> new file mode 100644
>>> index 000000000000..a4ed732b49c6
>>> --- /dev/null
>>> +++ b/tools/perf/arch/loongarch/util/header.c
>>> @@ -0,0 +1,88 @@
>>> +// SPDX-License-Identifier: GPL-2.0-only
>>> +/*
>>> + * Implementation of get_cpuid().
>>> + *
>>> + * Author: Nikita Shubin <n.shubin@yadro.com>
>>> + */
>>> +
>>> +#include <stdio.h>
>>> +#include <stdlib.h>
>>> +#include <api/fs/fs.h>
>>> +#include <errno.h>
>>> +#include "util/debug.h"
>>> +#include "util/header.h"
>>> +
>>> +/*
>>> + * Output example from /proc/cpuinfo
>>> + *   CPU Family              : Loongson-64bit
>>> + *   Model Name              : Loongson-3C5000
>>> + *   CPU Revision            : 0x11
>>> + */
>>> +#define CPUINFO_MODEL        "Model Name"
>>> +#define CPUINFO              "/proc/cpuinfo"
>>> +static char *_get_field(const char *line)
>>> +{
>>> +     char *line2, *nl;
>>> +
>>> +     line2 = strrchr(line, ' ');
>>> +     if (!line2)
>>> +             return NULL;
>>> +
>>> +     line2++;
>>> +     nl = strrchr(line, '\n');
>>> +     if (!nl)
>>> +             return NULL;
>>> +
>>> +     return strndup(line2, nl - line2);
>>> +}
>>> +
>>> +static char *__get_cpuid(void)
>>> +{
>>> +     char *line, *model, *cpuid;
>>> +     unsigned long line_sz;
>>> +     FILE *file;
>>> +
>>> +     file = fopen(CPUINFO, "r");
>>> +     if (file == NULL)
>>> +             return cpuid;
>>> +
>>> +     line = model = cpuid = NULL;
>>> +     while (getline(&line, &line_sz, file) != -1) {
>>> +             if (strncmp(line, CPUINFO_MODEL, strlen(CPUINFO_MODEL)))
>>> +                     continue;
>>> +
>>> +             model = _get_field(line);
>>> +             if (!model)
>>> +                     goto free;
>>> +             break;
>>> +     }
>>> +
>>> +     if (model && (asprintf(&cpuid, "%s", model) < 0))
>>> +             cpuid = NULL;
>>> +
>>> +free:
>>> +     fclose(file);
>>> +     free(model);
>>> +     return cpuid;
>>> +}
>>> +
>>> +int get_cpuid(char *buffer, size_t sz)
>>> +{
>>> +     char *cpuid = __get_cpuid();
>>> +     int ret = 0;
>>> +
>>> +     if (!cpuid)
>>> +             return EINVAL;
>>> +
>>> +     if (sz >= strlen(cpuid))
>>> +             scnprintf(buffer, sz, "%s", cpuid);
>>> +     else
>>> +             ret = ENOBUFS;
>>> +     free(cpuid);
>>> +     return ret;
>>> +}
>>> +
>>> +char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
>>> +{
>>> +     return __get_cpuid();
>>> +}
>>> diff --git a/tools/perf/arch/loongarch/util/kvm-stat.c b/tools/perf/arch/loongarch/util/kvm-stat.c
>>> new file mode 100644
>>> index 000000000000..cc50adb0835a
>>> --- /dev/null
>>> +++ b/tools/perf/arch/loongarch/util/kvm-stat.c
>>> @@ -0,0 +1,135 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +#include <errno.h>
>>> +#include <memory.h>
>>> +#include <errno.h>
>>> +#include "util/kvm-stat.h"
>>> +#include "util/parse-events.h"
>>> +#include "util/debug.h"
>>> +#include "util/evsel.h"
>>> +#include "util/evlist.h"
>>> +#include "util/pmus.h"
>>> +
>>> +#define LOONGARCH_EXCEPTION_INT              0
>>> +#define LOONGARCH_EXCEPTION_PIL              1
>>> +#define LOONGARCH_EXCEPTION_PIS              2
>>> +#define LOONGARCH_EXCEPTION_PIF              3
>>> +#define LOONGARCH_EXCEPTION_PME              4
>>> +#define LOONGARCH_EXCEPTION_FPD              15
>>> +#define LOONGARCH_EXCEPTION_SXD              16
>>> +#define LOONGARCH_EXCEPTION_ASXD     17
>>> +#define LOONGARCH_EXCEPTION_GSPR     22
>>> +#define  LOONGARCH_EXCEPTION_CPUCFG  100
>>> +#define  LOONGARCH_EXCEPTION_CSR     101
>>> +#define  LOONGARCH_EXCEPTION_IOCSR   102
>>> +#define  LOONGARCH_EXCEPTION_IDLE    103
>>> +#define  LOONGARCH_EXCEPTION_OTHERS  104
>>> +#define LOONGARCH_EXCEPTION_HVC              23
>>> +
>>> +#define loongarch_exception_type                             \
>>> +     {LOONGARCH_EXCEPTION_INT,  "Interrupt" },               \
>>> +     {LOONGARCH_EXCEPTION_PIL,  "Mem read" },                \
>>> +     {LOONGARCH_EXCEPTION_PIS,  "Mem store" },               \
>>> +     {LOONGARCH_EXCEPTION_PIF,  "Ifecth" },                  \
>>> +     {LOONGARCH_EXCEPTION_PME,  "Mem modify" },              \
>>> +     {LOONGARCH_EXCEPTION_FPD,  "FPU" },                     \
>>> +     {LOONGARCH_EXCEPTION_SXD,  "LSX" },                     \
>>> +     {LOONGARCH_EXCEPTION_ASXD, "LASX" },                    \
>>> +     {LOONGARCH_EXCEPTION_GSPR, "Privilege Error" },         \
>>> +     {LOONGARCH_EXCEPTION_HVC,  "Hypercall" },               \
>>> +     {LOONGARCH_EXCEPTION_CPUCFG, "Cpucfg" },                \
>>> +     {LOONGARCH_EXCEPTION_CSR,    "Csr" },                   \
>>> +     {LOONGARCH_EXCEPTION_IOCSR,  "Iocsr" },                 \
>>> +     {LOONGARCH_EXCEPTION_IDLE,   "Idle" },                  \
>>> +     {LOONGARCH_EXCEPTION_OTHERS, "Others" }
>>> +
>>> +define_exit_reasons_table(loongarch_exit_reasons, loongarch_exception_type);
>>> +
>>> +const char *vcpu_id_str = "vcpu_id";
>>> +const char *kvm_exit_reason = "reason";
>>> +const char *kvm_entry_trace = "kvm:kvm_enter";
>>> +const char *kvm_reenter_trace = "kvm:kvm_reenter";
>>> +const char *kvm_exit_trace = "kvm:kvm_exit";
>>> +const char *kvm_events_tp[] = {
>>> +     "kvm:kvm_enter",
>>> +     "kvm:kvm_reenter",
>>> +     "kvm:kvm_exit",
>>> +     "kvm:kvm_exit_gspr",
>>> +     NULL,
>>> +};
>>> +
>>> +static bool event_end(struct evsel *evsel,
>>> +             struct perf_sample *sample __maybe_unused,
>>> +             struct event_key *key __maybe_unused)
>>> +{
>>> +     /*
>>> +      * LoongArch kvm is different with other architectures
>>> +      *
>>> +      * There is kvm:kvm_reenter or kvm:kvm_enter event adjacent with
>>> +      * kvm:kvm_exit event.
>>> +      *   kvm:kvm_reenter means returning to guest immediately
>>> +      *   kvm:kvm_enter   means returning to vmm and then to guest
>>> +      */
>>> +     return evsel__name_is(evsel, kvm_entry_trace) ||
>>> +             evsel__name_is(evsel, kvm_reenter_trace);
>>> +}
>>> +
>>> +static void event_gspr_get_key(struct evsel *evsel,
>>> +                     struct perf_sample *sample,
>>> +                     struct event_key *key)
>>> +{
>>> +     unsigned int insn;
>>> +
>>> +     key->key = LOONGARCH_EXCEPTION_OTHERS;
>>> +     insn = evsel__intval(evsel, sample, "inst_word");
>>> +     switch (insn >> 24) {
>>> +     case 0:
>>> +             /* cpucfg inst trap */
>>> +             if ((insn >> 10) == 0x1b)
>>> +                     key->key = LOONGARCH_EXCEPTION_CPUCFG;
>>> +             break;
>>> +     case 4:
>>> +             /* csr inst trap */
>>> +             key->key = LOONGARCH_EXCEPTION_CSR;
>>> +             break;
>>> +     case 6:
>>> +             /* iocsr inst trap */
>>> +             if ((insn >> 15) == 0xc90)
>>> +                     key->key = LOONGARCH_EXCEPTION_IOCSR;
>>> +             else if ((insn >> 15) == 0xc91)
>>> +                     /* idle inst trap */
>>> +                     key->key = LOONGARCH_EXCEPTION_IDLE;
>>> +             break;
>>> +     default:
>>> +             key->key = LOONGARCH_EXCEPTION_OTHERS;
>>> +             break;
>>> +     }
>>> +}
>>> +
>>> +static struct child_event_ops child_events[] = {
>>> +     { .name = "kvm:kvm_exit_gspr", .get_key = event_gspr_get_key },
>>> +     { NULL, NULL },
>>> +};
>>> +
>>> +static struct kvm_events_ops exit_events = {
>>> +     .is_begin_event = exit_event_begin,
>>> +     .is_end_event = event_end,
>>> +     .child_ops = child_events,
>>> +     .decode_key = exit_event_decode_key,
>>> +     .name = "VM-EXIT"
>>> +};
>>> +
>>> +struct kvm_reg_events_ops kvm_reg_events_ops[] = {
>>> +     { .name = "vmexit", .ops = &exit_events, },
>>> +     { NULL, NULL },
>>> +};
>>> +
>>> +const char * const kvm_skip_events[] = {
>>> +     NULL,
>>> +};
>>> +
>>> +int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid __maybe_unused)
>>> +{
>>> +     kvm->exit_reasons_isa = "loongarch64";
>>> +     kvm->exit_reasons = loongarch_exit_reasons;
>>> +     return 0;
>>> +}
>>>
>>> base-commit: 2c71fdf02a95b3dd425b42f28fd47fb2b1d22702
>>>
>>


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] perf kvm: Add kvm-stat for loongarch64
  2024-05-10  1:47     ` maobibo
@ 2024-07-05  9:38       ` Huacai Chen
  0 siblings, 0 replies; 6+ messages in thread
From: Huacai Chen @ 2024-07-05  9:38 UTC (permalink / raw)
  To: maobibo
  Cc: Peter Zijlstra, Ian Rogers, Ming Wang, Ingo Molnar, linux-kernel,
	linux-perf-users

Applied, thanks.

Huacai

On Fri, May 10, 2024 at 9:47 AM maobibo <maobibo@loongson.cn> wrote:
>
>
>
> On 2024/5/8 下午9:02, Huacai Chen wrote:
> > On Tue, May 7, 2024 at 2:11 PM maobibo <maobibo@loongson.cn> wrote:
> >>
> >> Hi Peter/Ian/Huacai,
> >>
> >> This patch stays one month without response, I know you are busy and
> >> look through thousands of patch every day.
> >>
> >> Just one question, who has permission to merge perf kvm patch for
> >> LoongArch. Is it LoongArch maintainer or perf kvm maintainer?
> > It should probably go to perf tree, but if it is allowed, maybe I can
> > try to merge into LoongArch tree.
>
>   tools/perf/arch/loongarch/Makefile        |   1 +
>   tools/perf/arch/loongarch/util/Build      |   2 +
>   tools/perf/arch/loongarch/util/header.c   |  88 ++++++++++++++
>   tools/perf/arch/loongarch/util/kvm-stat.c | 135 ++++++++++++++++++++++
>
> All the modification is LoongArch specific, there will be much
> appreciated if it can reviewed and merged.
>
> Regards
> Bibo Mao
>
> >
> >
> > Huacai
> >>
> >> Regards
> >> Bibo Mao
> >>
> >>
> >> On 2024/4/11 下午8:10, Bibo Mao wrote:
> >>> Add support for 'perf kvm stat' on loongarch64 platform, now only
> >>> kvm exit event is supported.
> >>>
> >>> Here is example output about "perf kvm --host stat report" command
> >>>
> >>>      Event name   Samples   Sample%     Time (ns)   Time%   Mean Time (ns)
> >>>       Mem store     83969    51.00%     625697070   8.00%             7451
> >>>        Mem read     37641    22.00%     112485730   1.00%             2988
> >>>       Interrupt     15542     9.00%      20620190   0.00%             1326
> >>>           Iocsr     15207     9.00%      94296190   1.00%             6200
> >>>       Hypercall      4873     2.00%      12265280   0.00%             2516
> >>>            Idle      3713     2.00%    6322055860  87.00%          1702681
> >>>             FPU      1819     1.00%       2750300   0.00%             1511
> >>>          Ifecth       502     0.00%       1341740   0.00%             2672
> >>>      Mem modify       324     0.00%        602240   0.00%             1858
> >>>          Cpucfg        55     0.00%         77610   0.00%             1411
> >>>             Csr        12     0.00%         19690   0.00%             1640
> >>>            LASX         3     0.00%          4870   0.00%             1623
> >>>             LSX         2     0.00%          2100   0.00%             1050
> >>>
> >>> Signed-off-by: Bibo Mao <maobibo@loongson.cn>
> >>> ---
> >>> v2 --- v3:
> >>>     1. Add NULL check with cpuid in function get_cpuid()
> >>>     2. Add example output from /proc/cpuinfo before function get_cpuid()
> >>> v1 --- v2:
> >>>     1. Add child_ops for kvm exit event, split kvm:kvm_exit_gspr events
> >>> into cpucfg/csr/iocsr/idle child events by decoding detailed gspr
> >>> instruction.
> >>>     2. Remove some exception code type which does not happen in current
> >>> kvm implementation, such as meomry NR/NX/priviledge exception.
> >>> ---
> >>>    tools/perf/arch/loongarch/Makefile        |   1 +
> >>>    tools/perf/arch/loongarch/util/Build      |   2 +
> >>>    tools/perf/arch/loongarch/util/header.c   |  88 ++++++++++++++
> >>>    tools/perf/arch/loongarch/util/kvm-stat.c | 135 ++++++++++++++++++++++
> >>>    4 files changed, 226 insertions(+)
> >>>    create mode 100644 tools/perf/arch/loongarch/util/header.c
> >>>    create mode 100644 tools/perf/arch/loongarch/util/kvm-stat.c
> >>>
> >>> diff --git a/tools/perf/arch/loongarch/Makefile b/tools/perf/arch/loongarch/Makefile
> >>> index 3992a67a87d9..c89d6bb6b184 100644
> >>> --- a/tools/perf/arch/loongarch/Makefile
> >>> +++ b/tools/perf/arch/loongarch/Makefile
> >>> @@ -4,6 +4,7 @@ PERF_HAVE_DWARF_REGS := 1
> >>>    endif
> >>>    PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
> >>>    PERF_HAVE_JITDUMP := 1
> >>> +HAVE_KVM_STAT_SUPPORT := 1
> >>>
> >>>    #
> >>>    # Syscall table generation for perf
> >>> diff --git a/tools/perf/arch/loongarch/util/Build b/tools/perf/arch/loongarch/util/Build
> >>> index d776125a2d06..b12d374d7096 100644
> >>> --- a/tools/perf/arch/loongarch/util/Build
> >>> +++ b/tools/perf/arch/loongarch/util/Build
> >>> @@ -1,5 +1,7 @@
> >>> +perf-y += header.o
> >>>    perf-y += perf_regs.o
> >>>
> >>>    perf-$(CONFIG_DWARF)     += dwarf-regs.o
> >>>    perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
> >>>    perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> >>> +perf-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
> >>> diff --git a/tools/perf/arch/loongarch/util/header.c b/tools/perf/arch/loongarch/util/header.c
> >>> new file mode 100644
> >>> index 000000000000..a4ed732b49c6
> >>> --- /dev/null
> >>> +++ b/tools/perf/arch/loongarch/util/header.c
> >>> @@ -0,0 +1,88 @@
> >>> +// SPDX-License-Identifier: GPL-2.0-only
> >>> +/*
> >>> + * Implementation of get_cpuid().
> >>> + *
> >>> + * Author: Nikita Shubin <n.shubin@yadro.com>
> >>> + */
> >>> +
> >>> +#include <stdio.h>
> >>> +#include <stdlib.h>
> >>> +#include <api/fs/fs.h>
> >>> +#include <errno.h>
> >>> +#include "util/debug.h"
> >>> +#include "util/header.h"
> >>> +
> >>> +/*
> >>> + * Output example from /proc/cpuinfo
> >>> + *   CPU Family              : Loongson-64bit
> >>> + *   Model Name              : Loongson-3C5000
> >>> + *   CPU Revision            : 0x11
> >>> + */
> >>> +#define CPUINFO_MODEL        "Model Name"
> >>> +#define CPUINFO              "/proc/cpuinfo"
> >>> +static char *_get_field(const char *line)
> >>> +{
> >>> +     char *line2, *nl;
> >>> +
> >>> +     line2 = strrchr(line, ' ');
> >>> +     if (!line2)
> >>> +             return NULL;
> >>> +
> >>> +     line2++;
> >>> +     nl = strrchr(line, '\n');
> >>> +     if (!nl)
> >>> +             return NULL;
> >>> +
> >>> +     return strndup(line2, nl - line2);
> >>> +}
> >>> +
> >>> +static char *__get_cpuid(void)
> >>> +{
> >>> +     char *line, *model, *cpuid;
> >>> +     unsigned long line_sz;
> >>> +     FILE *file;
> >>> +
> >>> +     file = fopen(CPUINFO, "r");
> >>> +     if (file == NULL)
> >>> +             return cpuid;
> >>> +
> >>> +     line = model = cpuid = NULL;
> >>> +     while (getline(&line, &line_sz, file) != -1) {
> >>> +             if (strncmp(line, CPUINFO_MODEL, strlen(CPUINFO_MODEL)))
> >>> +                     continue;
> >>> +
> >>> +             model = _get_field(line);
> >>> +             if (!model)
> >>> +                     goto free;
> >>> +             break;
> >>> +     }
> >>> +
> >>> +     if (model && (asprintf(&cpuid, "%s", model) < 0))
> >>> +             cpuid = NULL;
> >>> +
> >>> +free:
> >>> +     fclose(file);
> >>> +     free(model);
> >>> +     return cpuid;
> >>> +}
> >>> +
> >>> +int get_cpuid(char *buffer, size_t sz)
> >>> +{
> >>> +     char *cpuid = __get_cpuid();
> >>> +     int ret = 0;
> >>> +
> >>> +     if (!cpuid)
> >>> +             return EINVAL;
> >>> +
> >>> +     if (sz >= strlen(cpuid))
> >>> +             scnprintf(buffer, sz, "%s", cpuid);
> >>> +     else
> >>> +             ret = ENOBUFS;
> >>> +     free(cpuid);
> >>> +     return ret;
> >>> +}
> >>> +
> >>> +char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
> >>> +{
> >>> +     return __get_cpuid();
> >>> +}
> >>> diff --git a/tools/perf/arch/loongarch/util/kvm-stat.c b/tools/perf/arch/loongarch/util/kvm-stat.c
> >>> new file mode 100644
> >>> index 000000000000..cc50adb0835a
> >>> --- /dev/null
> >>> +++ b/tools/perf/arch/loongarch/util/kvm-stat.c
> >>> @@ -0,0 +1,135 @@
> >>> +// SPDX-License-Identifier: GPL-2.0
> >>> +#include <errno.h>
> >>> +#include <memory.h>
> >>> +#include <errno.h>
> >>> +#include "util/kvm-stat.h"
> >>> +#include "util/parse-events.h"
> >>> +#include "util/debug.h"
> >>> +#include "util/evsel.h"
> >>> +#include "util/evlist.h"
> >>> +#include "util/pmus.h"
> >>> +
> >>> +#define LOONGARCH_EXCEPTION_INT              0
> >>> +#define LOONGARCH_EXCEPTION_PIL              1
> >>> +#define LOONGARCH_EXCEPTION_PIS              2
> >>> +#define LOONGARCH_EXCEPTION_PIF              3
> >>> +#define LOONGARCH_EXCEPTION_PME              4
> >>> +#define LOONGARCH_EXCEPTION_FPD              15
> >>> +#define LOONGARCH_EXCEPTION_SXD              16
> >>> +#define LOONGARCH_EXCEPTION_ASXD     17
> >>> +#define LOONGARCH_EXCEPTION_GSPR     22
> >>> +#define  LOONGARCH_EXCEPTION_CPUCFG  100
> >>> +#define  LOONGARCH_EXCEPTION_CSR     101
> >>> +#define  LOONGARCH_EXCEPTION_IOCSR   102
> >>> +#define  LOONGARCH_EXCEPTION_IDLE    103
> >>> +#define  LOONGARCH_EXCEPTION_OTHERS  104
> >>> +#define LOONGARCH_EXCEPTION_HVC              23
> >>> +
> >>> +#define loongarch_exception_type                             \
> >>> +     {LOONGARCH_EXCEPTION_INT,  "Interrupt" },               \
> >>> +     {LOONGARCH_EXCEPTION_PIL,  "Mem read" },                \
> >>> +     {LOONGARCH_EXCEPTION_PIS,  "Mem store" },               \
> >>> +     {LOONGARCH_EXCEPTION_PIF,  "Ifecth" },                  \
> >>> +     {LOONGARCH_EXCEPTION_PME,  "Mem modify" },              \
> >>> +     {LOONGARCH_EXCEPTION_FPD,  "FPU" },                     \
> >>> +     {LOONGARCH_EXCEPTION_SXD,  "LSX" },                     \
> >>> +     {LOONGARCH_EXCEPTION_ASXD, "LASX" },                    \
> >>> +     {LOONGARCH_EXCEPTION_GSPR, "Privilege Error" },         \
> >>> +     {LOONGARCH_EXCEPTION_HVC,  "Hypercall" },               \
> >>> +     {LOONGARCH_EXCEPTION_CPUCFG, "Cpucfg" },                \
> >>> +     {LOONGARCH_EXCEPTION_CSR,    "Csr" },                   \
> >>> +     {LOONGARCH_EXCEPTION_IOCSR,  "Iocsr" },                 \
> >>> +     {LOONGARCH_EXCEPTION_IDLE,   "Idle" },                  \
> >>> +     {LOONGARCH_EXCEPTION_OTHERS, "Others" }
> >>> +
> >>> +define_exit_reasons_table(loongarch_exit_reasons, loongarch_exception_type);
> >>> +
> >>> +const char *vcpu_id_str = "vcpu_id";
> >>> +const char *kvm_exit_reason = "reason";
> >>> +const char *kvm_entry_trace = "kvm:kvm_enter";
> >>> +const char *kvm_reenter_trace = "kvm:kvm_reenter";
> >>> +const char *kvm_exit_trace = "kvm:kvm_exit";
> >>> +const char *kvm_events_tp[] = {
> >>> +     "kvm:kvm_enter",
> >>> +     "kvm:kvm_reenter",
> >>> +     "kvm:kvm_exit",
> >>> +     "kvm:kvm_exit_gspr",
> >>> +     NULL,
> >>> +};
> >>> +
> >>> +static bool event_end(struct evsel *evsel,
> >>> +             struct perf_sample *sample __maybe_unused,
> >>> +             struct event_key *key __maybe_unused)
> >>> +{
> >>> +     /*
> >>> +      * LoongArch kvm is different with other architectures
> >>> +      *
> >>> +      * There is kvm:kvm_reenter or kvm:kvm_enter event adjacent with
> >>> +      * kvm:kvm_exit event.
> >>> +      *   kvm:kvm_reenter means returning to guest immediately
> >>> +      *   kvm:kvm_enter   means returning to vmm and then to guest
> >>> +      */
> >>> +     return evsel__name_is(evsel, kvm_entry_trace) ||
> >>> +             evsel__name_is(evsel, kvm_reenter_trace);
> >>> +}
> >>> +
> >>> +static void event_gspr_get_key(struct evsel *evsel,
> >>> +                     struct perf_sample *sample,
> >>> +                     struct event_key *key)
> >>> +{
> >>> +     unsigned int insn;
> >>> +
> >>> +     key->key = LOONGARCH_EXCEPTION_OTHERS;
> >>> +     insn = evsel__intval(evsel, sample, "inst_word");
> >>> +     switch (insn >> 24) {
> >>> +     case 0:
> >>> +             /* cpucfg inst trap */
> >>> +             if ((insn >> 10) == 0x1b)
> >>> +                     key->key = LOONGARCH_EXCEPTION_CPUCFG;
> >>> +             break;
> >>> +     case 4:
> >>> +             /* csr inst trap */
> >>> +             key->key = LOONGARCH_EXCEPTION_CSR;
> >>> +             break;
> >>> +     case 6:
> >>> +             /* iocsr inst trap */
> >>> +             if ((insn >> 15) == 0xc90)
> >>> +                     key->key = LOONGARCH_EXCEPTION_IOCSR;
> >>> +             else if ((insn >> 15) == 0xc91)
> >>> +                     /* idle inst trap */
> >>> +                     key->key = LOONGARCH_EXCEPTION_IDLE;
> >>> +             break;
> >>> +     default:
> >>> +             key->key = LOONGARCH_EXCEPTION_OTHERS;
> >>> +             break;
> >>> +     }
> >>> +}
> >>> +
> >>> +static struct child_event_ops child_events[] = {
> >>> +     { .name = "kvm:kvm_exit_gspr", .get_key = event_gspr_get_key },
> >>> +     { NULL, NULL },
> >>> +};
> >>> +
> >>> +static struct kvm_events_ops exit_events = {
> >>> +     .is_begin_event = exit_event_begin,
> >>> +     .is_end_event = event_end,
> >>> +     .child_ops = child_events,
> >>> +     .decode_key = exit_event_decode_key,
> >>> +     .name = "VM-EXIT"
> >>> +};
> >>> +
> >>> +struct kvm_reg_events_ops kvm_reg_events_ops[] = {
> >>> +     { .name = "vmexit", .ops = &exit_events, },
> >>> +     { NULL, NULL },
> >>> +};
> >>> +
> >>> +const char * const kvm_skip_events[] = {
> >>> +     NULL,
> >>> +};
> >>> +
> >>> +int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid __maybe_unused)
> >>> +{
> >>> +     kvm->exit_reasons_isa = "loongarch64";
> >>> +     kvm->exit_reasons = loongarch_exit_reasons;
> >>> +     return 0;
> >>> +}
> >>>
> >>> base-commit: 2c71fdf02a95b3dd425b42f28fd47fb2b1d22702
> >>>
> >>
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2024-07-05  9:38 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-04-11 12:10 [PATCH v3] perf kvm: Add kvm-stat for loongarch64 Bibo Mao
2024-04-19  2:34 ` maobibo
2024-05-07  6:10 ` maobibo
2024-05-08 13:02   ` Huacai Chen
2024-05-10  1:47     ` maobibo
2024-07-05  9:38       ` Huacai Chen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).