2 #include "../../util/kvm-stat.h"
7 define_exit_reasons_table(vmx_exit_reasons
, VMX_EXIT_REASONS
);
8 define_exit_reasons_table(svm_exit_reasons
, SVM_EXIT_REASONS
);
10 static struct kvm_events_ops exit_events
= {
11 .is_begin_event
= exit_event_begin
,
12 .is_end_event
= exit_event_end
,
13 .decode_key
= exit_event_decode_key
,
17 const char *vcpu_id_str
= "vcpu_id";
18 const int decode_str_len
= 20;
19 const char *kvm_exit_reason
= "exit_reason";
20 const char *kvm_entry_trace
= "kvm:kvm_entry";
21 const char *kvm_exit_trace
= "kvm:kvm_exit";
24 * For the mmio events, we treat:
25 * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
26 * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...).
28 static void mmio_event_get_key(struct perf_evsel
*evsel
, struct perf_sample
*sample
,
29 struct event_key
*key
)
31 key
->key
= perf_evsel__intval(evsel
, sample
, "gpa");
32 key
->info
= perf_evsel__intval(evsel
, sample
, "type");
35 #define KVM_TRACE_MMIO_READ_UNSATISFIED 0
36 #define KVM_TRACE_MMIO_READ 1
37 #define KVM_TRACE_MMIO_WRITE 2
39 static bool mmio_event_begin(struct perf_evsel
*evsel
,
40 struct perf_sample
*sample
, struct event_key
*key
)
42 /* MMIO read begin event in kernel. */
43 if (kvm_exit_event(evsel
))
46 /* MMIO write begin event in kernel. */
47 if (!strcmp(evsel
->name
, "kvm:kvm_mmio") &&
48 perf_evsel__intval(evsel
, sample
, "type") == KVM_TRACE_MMIO_WRITE
) {
49 mmio_event_get_key(evsel
, sample
, key
);
56 static bool mmio_event_end(struct perf_evsel
*evsel
, struct perf_sample
*sample
,
57 struct event_key
*key
)
59 /* MMIO write end event in kernel. */
60 if (kvm_entry_event(evsel
))
63 /* MMIO read end event in kernel.*/
64 if (!strcmp(evsel
->name
, "kvm:kvm_mmio") &&
65 perf_evsel__intval(evsel
, sample
, "type") == KVM_TRACE_MMIO_READ
) {
66 mmio_event_get_key(evsel
, sample
, key
);
73 static void mmio_event_decode_key(struct perf_kvm_stat
*kvm __maybe_unused
,
74 struct event_key
*key
,
77 scnprintf(decode
, decode_str_len
, "%#lx:%s",
78 (unsigned long)key
->key
,
79 key
->info
== KVM_TRACE_MMIO_WRITE
? "W" : "R");
82 static struct kvm_events_ops mmio_events
= {
83 .is_begin_event
= mmio_event_begin
,
84 .is_end_event
= mmio_event_end
,
85 .decode_key
= mmio_event_decode_key
,
89 /* The time of emulation pio access is from kvm_pio to kvm_entry. */
90 static void ioport_event_get_key(struct perf_evsel
*evsel
,
91 struct perf_sample
*sample
,
92 struct event_key
*key
)
94 key
->key
= perf_evsel__intval(evsel
, sample
, "port");
95 key
->info
= perf_evsel__intval(evsel
, sample
, "rw");
98 static bool ioport_event_begin(struct perf_evsel
*evsel
,
99 struct perf_sample
*sample
,
100 struct event_key
*key
)
102 if (!strcmp(evsel
->name
, "kvm:kvm_pio")) {
103 ioport_event_get_key(evsel
, sample
, key
);
110 static bool ioport_event_end(struct perf_evsel
*evsel
,
111 struct perf_sample
*sample __maybe_unused
,
112 struct event_key
*key __maybe_unused
)
114 return kvm_entry_event(evsel
);
117 static void ioport_event_decode_key(struct perf_kvm_stat
*kvm __maybe_unused
,
118 struct event_key
*key
,
121 scnprintf(decode
, decode_str_len
, "%#llx:%s",
122 (unsigned long long)key
->key
,
123 key
->info
? "POUT" : "PIN");
126 static struct kvm_events_ops ioport_events
= {
127 .is_begin_event
= ioport_event_begin
,
128 .is_end_event
= ioport_event_end
,
129 .decode_key
= ioport_event_decode_key
,
130 .name
= "IO Port Access"
133 const char *kvm_events_tp
[] = {
141 struct kvm_reg_events_ops kvm_reg_events_ops
[] = {
142 { .name
= "vmexit", .ops
= &exit_events
},
143 { .name
= "mmio", .ops
= &mmio_events
},
144 { .name
= "ioport", .ops
= &ioport_events
},
148 const char * const kvm_skip_events
[] = {
153 int cpu_isa_init(struct perf_kvm_stat
*kvm
, const char *cpuid
)
155 if (strstr(cpuid
, "Intel")) {
156 kvm
->exit_reasons
= vmx_exit_reasons
;
157 kvm
->exit_reasons_isa
= "VMX";
158 } else if (strstr(cpuid
, "AMD")) {
159 kvm
->exit_reasons
= svm_exit_reasons
;
160 kvm
->exit_reasons_isa
= "SVM";