1 #include "../../util/kvm-stat.h"
6 define_exit_reasons_table(vmx_exit_reasons
, VMX_EXIT_REASONS
);
7 define_exit_reasons_table(svm_exit_reasons
, SVM_EXIT_REASONS
);
9 static struct kvm_events_ops exit_events
= {
10 .is_begin_event
= exit_event_begin
,
11 .is_end_event
= exit_event_end
,
12 .decode_key
= exit_event_decode_key
,
16 const char *vcpu_id_str
= "vcpu_id";
17 const int decode_str_len
= 20;
18 const char *kvm_exit_reason
= "exit_reason";
19 const char *kvm_entry_trace
= "kvm:kvm_entry";
20 const char *kvm_exit_trace
= "kvm:kvm_exit";
23 * For the mmio events, we treat:
24 * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
25 * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...).
27 static void mmio_event_get_key(struct perf_evsel
*evsel
, struct perf_sample
*sample
,
28 struct event_key
*key
)
30 key
->key
= perf_evsel__intval(evsel
, sample
, "gpa");
31 key
->info
= perf_evsel__intval(evsel
, sample
, "type");
34 #define KVM_TRACE_MMIO_READ_UNSATISFIED 0
35 #define KVM_TRACE_MMIO_READ 1
36 #define KVM_TRACE_MMIO_WRITE 2
38 static bool mmio_event_begin(struct perf_evsel
*evsel
,
39 struct perf_sample
*sample
, struct event_key
*key
)
41 /* MMIO read begin event in kernel. */
42 if (kvm_exit_event(evsel
))
45 /* MMIO write begin event in kernel. */
46 if (!strcmp(evsel
->name
, "kvm:kvm_mmio") &&
47 perf_evsel__intval(evsel
, sample
, "type") == KVM_TRACE_MMIO_WRITE
) {
48 mmio_event_get_key(evsel
, sample
, key
);
55 static bool mmio_event_end(struct perf_evsel
*evsel
, struct perf_sample
*sample
,
56 struct event_key
*key
)
58 /* MMIO write end event in kernel. */
59 if (kvm_entry_event(evsel
))
62 /* MMIO read end event in kernel.*/
63 if (!strcmp(evsel
->name
, "kvm:kvm_mmio") &&
64 perf_evsel__intval(evsel
, sample
, "type") == KVM_TRACE_MMIO_READ
) {
65 mmio_event_get_key(evsel
, sample
, key
);
72 static void mmio_event_decode_key(struct perf_kvm_stat
*kvm __maybe_unused
,
73 struct event_key
*key
,
76 scnprintf(decode
, decode_str_len
, "%#lx:%s",
77 (unsigned long)key
->key
,
78 key
->info
== KVM_TRACE_MMIO_WRITE
? "W" : "R");
81 static struct kvm_events_ops mmio_events
= {
82 .is_begin_event
= mmio_event_begin
,
83 .is_end_event
= mmio_event_end
,
84 .decode_key
= mmio_event_decode_key
,
88 /* The time of emulation pio access is from kvm_pio to kvm_entry. */
89 static void ioport_event_get_key(struct perf_evsel
*evsel
,
90 struct perf_sample
*sample
,
91 struct event_key
*key
)
93 key
->key
= perf_evsel__intval(evsel
, sample
, "port");
94 key
->info
= perf_evsel__intval(evsel
, sample
, "rw");
97 static bool ioport_event_begin(struct perf_evsel
*evsel
,
98 struct perf_sample
*sample
,
99 struct event_key
*key
)
101 if (!strcmp(evsel
->name
, "kvm:kvm_pio")) {
102 ioport_event_get_key(evsel
, sample
, key
);
109 static bool ioport_event_end(struct perf_evsel
*evsel
,
110 struct perf_sample
*sample __maybe_unused
,
111 struct event_key
*key __maybe_unused
)
113 return kvm_entry_event(evsel
);
116 static void ioport_event_decode_key(struct perf_kvm_stat
*kvm __maybe_unused
,
117 struct event_key
*key
,
120 scnprintf(decode
, decode_str_len
, "%#llx:%s",
121 (unsigned long long)key
->key
,
122 key
->info
? "POUT" : "PIN");
125 static struct kvm_events_ops ioport_events
= {
126 .is_begin_event
= ioport_event_begin
,
127 .is_end_event
= ioport_event_end
,
128 .decode_key
= ioport_event_decode_key
,
129 .name
= "IO Port Access"
132 const char *kvm_events_tp
[] = {
140 struct kvm_reg_events_ops kvm_reg_events_ops
[] = {
141 { .name
= "vmexit", .ops
= &exit_events
},
142 { .name
= "mmio", .ops
= &mmio_events
},
143 { .name
= "ioport", .ops
= &ioport_events
},
147 const char * const kvm_skip_events
[] = {
152 int cpu_isa_init(struct perf_kvm_stat
*kvm
, const char *cpuid
)
154 if (strstr(cpuid
, "Intel")) {
155 kvm
->exit_reasons
= vmx_exit_reasons
;
156 kvm
->exit_reasons_isa
= "VMX";
157 } else if (strstr(cpuid
, "AMD")) {
158 kvm
->exit_reasons
= svm_exit_reasons
;
159 kvm
->exit_reasons_isa
= "SVM";