Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/perf/arch/x86/util/kvm-stat.c
26289 views
1
// SPDX-License-Identifier: GPL-2.0
2
#include <errno.h>
3
#include <string.h>
4
#include "../../../util/kvm-stat.h"
5
#include "../../../util/evsel.h"
6
#include <asm/svm.h>
7
#include <asm/vmx.h>
8
#include <asm/kvm.h>
9
10
define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS);
11
define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS);
12
13
static struct kvm_events_ops exit_events = {
14
.is_begin_event = exit_event_begin,
15
.is_end_event = exit_event_end,
16
.decode_key = exit_event_decode_key,
17
.name = "VM-EXIT"
18
};
19
20
const char *vcpu_id_str = "vcpu_id";
21
const char *kvm_exit_reason = "exit_reason";
22
const char *kvm_entry_trace = "kvm:kvm_entry";
23
const char *kvm_exit_trace = "kvm:kvm_exit";
24
25
/*
26
* For the mmio events, we treat:
27
* the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
28
* the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...).
29
*/
30
static void mmio_event_get_key(struct evsel *evsel, struct perf_sample *sample,
31
struct event_key *key)
32
{
33
key->key = evsel__intval(evsel, sample, "gpa");
34
key->info = evsel__intval(evsel, sample, "type");
35
}
36
37
#define KVM_TRACE_MMIO_READ_UNSATISFIED 0
38
#define KVM_TRACE_MMIO_READ 1
39
#define KVM_TRACE_MMIO_WRITE 2
40
41
static bool mmio_event_begin(struct evsel *evsel,
42
struct perf_sample *sample, struct event_key *key)
43
{
44
/* MMIO read begin event in kernel. */
45
if (kvm_exit_event(evsel))
46
return true;
47
48
/* MMIO write begin event in kernel. */
49
if (evsel__name_is(evsel, "kvm:kvm_mmio") &&
50
evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) {
51
mmio_event_get_key(evsel, sample, key);
52
return true;
53
}
54
55
return false;
56
}
57
58
static bool mmio_event_end(struct evsel *evsel, struct perf_sample *sample,
59
struct event_key *key)
60
{
61
/* MMIO write end event in kernel. */
62
if (kvm_entry_event(evsel))
63
return true;
64
65
/* MMIO read end event in kernel.*/
66
if (evsel__name_is(evsel, "kvm:kvm_mmio") &&
67
evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) {
68
mmio_event_get_key(evsel, sample, key);
69
return true;
70
}
71
72
return false;
73
}
74
75
static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
76
struct event_key *key,
77
char *decode)
78
{
79
scnprintf(decode, KVM_EVENT_NAME_LEN, "%#lx:%s",
80
(unsigned long)key->key,
81
key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R");
82
}
83
84
static struct kvm_events_ops mmio_events = {
85
.is_begin_event = mmio_event_begin,
86
.is_end_event = mmio_event_end,
87
.decode_key = mmio_event_decode_key,
88
.name = "MMIO Access"
89
};
90
91
/* The time of emulation pio access is from kvm_pio to kvm_entry. */
92
static void ioport_event_get_key(struct evsel *evsel,
93
struct perf_sample *sample,
94
struct event_key *key)
95
{
96
key->key = evsel__intval(evsel, sample, "port");
97
key->info = evsel__intval(evsel, sample, "rw");
98
}
99
100
static bool ioport_event_begin(struct evsel *evsel,
101
struct perf_sample *sample,
102
struct event_key *key)
103
{
104
if (evsel__name_is(evsel, "kvm:kvm_pio")) {
105
ioport_event_get_key(evsel, sample, key);
106
return true;
107
}
108
109
return false;
110
}
111
112
static bool ioport_event_end(struct evsel *evsel,
113
struct perf_sample *sample __maybe_unused,
114
struct event_key *key __maybe_unused)
115
{
116
return kvm_entry_event(evsel);
117
}
118
119
static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
120
struct event_key *key,
121
char *decode)
122
{
123
scnprintf(decode, KVM_EVENT_NAME_LEN, "%#llx:%s",
124
(unsigned long long)key->key,
125
key->info ? "POUT" : "PIN");
126
}
127
128
static struct kvm_events_ops ioport_events = {
129
.is_begin_event = ioport_event_begin,
130
.is_end_event = ioport_event_end,
131
.decode_key = ioport_event_decode_key,
132
.name = "IO Port Access"
133
};
134
135
/* The time of emulation msr is from kvm_msr to kvm_entry. */
136
static void msr_event_get_key(struct evsel *evsel,
137
struct perf_sample *sample,
138
struct event_key *key)
139
{
140
key->key = evsel__intval(evsel, sample, "ecx");
141
key->info = evsel__intval(evsel, sample, "write");
142
}
143
144
static bool msr_event_begin(struct evsel *evsel,
145
struct perf_sample *sample,
146
struct event_key *key)
147
{
148
if (evsel__name_is(evsel, "kvm:kvm_msr")) {
149
msr_event_get_key(evsel, sample, key);
150
return true;
151
}
152
153
return false;
154
}
155
156
static bool msr_event_end(struct evsel *evsel,
157
struct perf_sample *sample __maybe_unused,
158
struct event_key *key __maybe_unused)
159
{
160
return kvm_entry_event(evsel);
161
}
162
163
static void msr_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
164
struct event_key *key,
165
char *decode)
166
{
167
scnprintf(decode, KVM_EVENT_NAME_LEN, "%#llx:%s",
168
(unsigned long long)key->key,
169
key->info ? "W" : "R");
170
}
171
172
static struct kvm_events_ops msr_events = {
173
.is_begin_event = msr_event_begin,
174
.is_end_event = msr_event_end,
175
.decode_key = msr_event_decode_key,
176
.name = "MSR Access"
177
};
178
179
const char *kvm_events_tp[] = {
180
"kvm:kvm_entry",
181
"kvm:kvm_exit",
182
"kvm:kvm_mmio",
183
"kvm:kvm_pio",
184
"kvm:kvm_msr",
185
NULL,
186
};
187
188
struct kvm_reg_events_ops kvm_reg_events_ops[] = {
189
{ .name = "vmexit", .ops = &exit_events },
190
{ .name = "mmio", .ops = &mmio_events },
191
{ .name = "ioport", .ops = &ioport_events },
192
{ .name = "msr", .ops = &msr_events },
193
{ NULL, NULL },
194
};
195
196
const char * const kvm_skip_events[] = {
197
"HLT",
198
NULL,
199
};
200
201
int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid)
202
{
203
if (strstr(cpuid, "Intel")) {
204
kvm->exit_reasons = vmx_exit_reasons;
205
kvm->exit_reasons_isa = "VMX";
206
} else if (strstr(cpuid, "AMD") || strstr(cpuid, "Hygon")) {
207
kvm->exit_reasons = svm_exit_reasons;
208
kvm->exit_reasons_isa = "SVM";
209
} else
210
return -ENOTSUP;
211
212
return 0;
213
}
214
215