Skip to content

Commit 492ac37

Browse files
bibo-maochenhuacai
authored andcommitted
perf kvm: Add kvm-stat for loongarch64
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 Inst Fetch 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 <[email protected]> Signed-off-by: Huacai Chen <[email protected]>
1 parent 0377999 commit 492ac37

File tree

4 files changed

+238
-0
lines changed

4 files changed

+238
-0
lines changed

tools/perf/arch/loongarch/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ PERF_HAVE_DWARF_REGS := 1
44
endif
55
PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
66
PERF_HAVE_JITDUMP := 1
7+
HAVE_KVM_STAT_SUPPORT := 1
78

89
#
910
# Syscall table generation for perf

tools/perf/arch/loongarch/util/Build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
perf-y += header.o
12
perf-y += perf_regs.o
23

34
perf-$(CONFIG_DWARF) += dwarf-regs.o
45
perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
56
perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
7+
perf-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Implementation of get_cpuid().
4+
*
5+
* Author: Nikita Shubin <[email protected]>
6+
* Bibo Mao <[email protected]>
7+
* Huacai Chen <[email protected]>
8+
*/
9+
10+
#include <stdio.h>
11+
#include <stdlib.h>
12+
#include <api/fs/fs.h>
13+
#include <errno.h>
14+
#include "util/debug.h"
15+
#include "util/header.h"
16+
17+
/*
18+
* Output example from /proc/cpuinfo
19+
* CPU Family : Loongson-64bit
20+
* Model Name : Loongson-3C5000
21+
* CPU Revision : 0x10
22+
* FPU Revision : 0x01
23+
*/
24+
#define CPUINFO_MODEL "Model Name"
25+
#define CPUINFO "/proc/cpuinfo"
26+
27+
static char *_get_field(const char *line)
28+
{
29+
char *line2, *nl;
30+
31+
line2 = strrchr(line, ' ');
32+
if (!line2)
33+
return NULL;
34+
35+
line2++;
36+
nl = strrchr(line, '\n');
37+
if (!nl)
38+
return NULL;
39+
40+
return strndup(line2, nl - line2);
41+
}
42+
43+
static char *_get_cpuid(void)
44+
{
45+
unsigned long line_sz;
46+
char *line, *model, *cpuid;
47+
FILE *file;
48+
49+
file = fopen(CPUINFO, "r");
50+
if (file == NULL)
51+
return NULL;
52+
53+
line = model = cpuid = NULL;
54+
while (getline(&line, &line_sz, file) != -1) {
55+
if (strncmp(line, CPUINFO_MODEL, strlen(CPUINFO_MODEL)))
56+
continue;
57+
58+
model = _get_field(line);
59+
if (!model)
60+
goto out_free;
61+
break;
62+
}
63+
64+
if (model && (asprintf(&cpuid, "%s", model) < 0))
65+
cpuid = NULL;
66+
67+
out_free:
68+
fclose(file);
69+
free(model);
70+
return cpuid;
71+
}
72+
73+
int get_cpuid(char *buffer, size_t sz)
74+
{
75+
int ret = 0;
76+
char *cpuid = _get_cpuid();
77+
78+
if (!cpuid)
79+
return EINVAL;
80+
81+
if (sz < strlen(cpuid)) {
82+
ret = ENOBUFS;
83+
goto out_free;
84+
}
85+
86+
scnprintf(buffer, sz, "%s", cpuid);
87+
88+
out_free:
89+
free(cpuid);
90+
return ret;
91+
}
92+
93+
char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
94+
{
95+
return _get_cpuid();
96+
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <errno.h>
3+
#include <memory.h>
4+
#include "util/kvm-stat.h"
5+
#include "util/parse-events.h"
6+
#include "util/debug.h"
7+
#include "util/evsel.h"
8+
#include "util/evlist.h"
9+
#include "util/pmus.h"
10+
11+
#define LOONGARCH_EXCEPTION_INT 0
12+
#define LOONGARCH_EXCEPTION_PIL 1
13+
#define LOONGARCH_EXCEPTION_PIS 2
14+
#define LOONGARCH_EXCEPTION_PIF 3
15+
#define LOONGARCH_EXCEPTION_PME 4
16+
#define LOONGARCH_EXCEPTION_FPD 15
17+
#define LOONGARCH_EXCEPTION_SXD 16
18+
#define LOONGARCH_EXCEPTION_ASXD 17
19+
#define LOONGARCH_EXCEPTION_GSPR 22
20+
#define LOONGARCH_EXCEPTION_CPUCFG 100
21+
#define LOONGARCH_EXCEPTION_CSR 101
22+
#define LOONGARCH_EXCEPTION_IOCSR 102
23+
#define LOONGARCH_EXCEPTION_IDLE 103
24+
#define LOONGARCH_EXCEPTION_OTHERS 104
25+
#define LOONGARCH_EXCEPTION_HVC 23
26+
27+
#define loongarch_exception_type \
28+
{LOONGARCH_EXCEPTION_INT, "Interrupt" }, \
29+
{LOONGARCH_EXCEPTION_PIL, "Mem Read" }, \
30+
{LOONGARCH_EXCEPTION_PIS, "Mem Store" }, \
31+
{LOONGARCH_EXCEPTION_PIF, "Inst Fetch" }, \
32+
{LOONGARCH_EXCEPTION_PME, "Mem Modify" }, \
33+
{LOONGARCH_EXCEPTION_FPD, "FPU" }, \
34+
{LOONGARCH_EXCEPTION_SXD, "LSX" }, \
35+
{LOONGARCH_EXCEPTION_ASXD, "LASX" }, \
36+
{LOONGARCH_EXCEPTION_GSPR, "Privilege Error" }, \
37+
{LOONGARCH_EXCEPTION_HVC, "Hypercall" }, \
38+
{LOONGARCH_EXCEPTION_CPUCFG, "CPUCFG" }, \
39+
{LOONGARCH_EXCEPTION_CSR, "CSR" }, \
40+
{LOONGARCH_EXCEPTION_IOCSR, "IOCSR" }, \
41+
{LOONGARCH_EXCEPTION_IDLE, "Idle" }, \
42+
{LOONGARCH_EXCEPTION_OTHERS, "Others" }
43+
44+
define_exit_reasons_table(loongarch_exit_reasons, loongarch_exception_type);
45+
46+
const char *vcpu_id_str = "vcpu_id";
47+
const char *kvm_exit_reason = "reason";
48+
const char *kvm_entry_trace = "kvm:kvm_enter";
49+
const char *kvm_reenter_trace = "kvm:kvm_reenter";
50+
const char *kvm_exit_trace = "kvm:kvm_exit";
51+
const char *kvm_events_tp[] = {
52+
"kvm:kvm_enter",
53+
"kvm:kvm_reenter",
54+
"kvm:kvm_exit",
55+
"kvm:kvm_exit_gspr",
56+
NULL,
57+
};
58+
59+
static bool event_begin(struct evsel *evsel,
60+
struct perf_sample *sample, struct event_key *key)
61+
{
62+
return exit_event_begin(evsel, sample, key);
63+
}
64+
65+
static bool event_end(struct evsel *evsel,
66+
struct perf_sample *sample __maybe_unused,
67+
struct event_key *key __maybe_unused)
68+
{
69+
/*
70+
* LoongArch kvm is different with other architectures
71+
*
72+
* There is kvm:kvm_reenter or kvm:kvm_enter event adjacent with
73+
* kvm:kvm_exit event.
74+
* kvm:kvm_enter means returning to vmm and then to guest
75+
* kvm:kvm_reenter means returning to guest immediately
76+
*/
77+
return evsel__name_is(evsel, kvm_entry_trace) || evsel__name_is(evsel, kvm_reenter_trace);
78+
}
79+
80+
static void event_gspr_get_key(struct evsel *evsel,
81+
struct perf_sample *sample, struct event_key *key)
82+
{
83+
unsigned int insn;
84+
85+
key->key = LOONGARCH_EXCEPTION_OTHERS;
86+
insn = evsel__intval(evsel, sample, "inst_word");
87+
88+
switch (insn >> 24) {
89+
case 0:
90+
/* CPUCFG inst trap */
91+
if ((insn >> 10) == 0x1b)
92+
key->key = LOONGARCH_EXCEPTION_CPUCFG;
93+
break;
94+
case 4:
95+
/* CSR inst trap */
96+
key->key = LOONGARCH_EXCEPTION_CSR;
97+
break;
98+
case 6:
99+
/* IOCSR inst trap */
100+
if ((insn >> 15) == 0xc90)
101+
key->key = LOONGARCH_EXCEPTION_IOCSR;
102+
else if ((insn >> 15) == 0xc91)
103+
/* Idle inst trap */
104+
key->key = LOONGARCH_EXCEPTION_IDLE;
105+
break;
106+
default:
107+
key->key = LOONGARCH_EXCEPTION_OTHERS;
108+
break;
109+
}
110+
}
111+
112+
static struct child_event_ops child_events[] = {
113+
{ .name = "kvm:kvm_exit_gspr", .get_key = event_gspr_get_key },
114+
{ NULL, NULL },
115+
};
116+
117+
static struct kvm_events_ops exit_events = {
118+
.is_begin_event = event_begin,
119+
.is_end_event = event_end,
120+
.child_ops = child_events,
121+
.decode_key = exit_event_decode_key,
122+
.name = "VM-EXIT"
123+
};
124+
125+
struct kvm_reg_events_ops kvm_reg_events_ops[] = {
126+
{ .name = "vmexit", .ops = &exit_events, },
127+
{ NULL, NULL },
128+
};
129+
130+
const char * const kvm_skip_events[] = {
131+
NULL,
132+
};
133+
134+
int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid __maybe_unused)
135+
{
136+
kvm->exit_reasons_isa = "loongarch64";
137+
kvm->exit_reasons = loongarch_exit_reasons;
138+
return 0;
139+
}

0 commit comments

Comments
 (0)