diff options
author | Alexander Yarygin <yarygin@linux.vnet.ibm.com> | 2014-07-03 10:29:05 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2014-07-16 16:57:32 -0400 |
commit | 9daa81239e60c162153fb2a365b8492c9a9bf632 (patch) | |
tree | a3f2fda3d42857f6c2d5188c308e02474d641eef /tools/perf/arch/x86/util/kvm-stat.c | |
parent | 44b3802122174ba499613bac3aab2e66e948ce1e (diff) |
perf kvm: Move arch specific code into arch/
Parts of a 'perf kvm stat' code make sense only for x86.
Let's move this code into the arch/x86/kvm-stat.c file and add
util/kvm-stat.h for generic structure definitions.
Add a global array 'kvm_reg_events_ops' for accessing the arch-specific
'kvm_events_ops' from generic code.
Since the several global arrays (i.e. 'kvm_events_tp') have been moved
to arch/*, we can not know their sizes and use them directly in
builtin-kvm.c. This patch fixes that problem by adding trimming NULL
element to each array and changing the behavior of their handlers in
generic code.
Reviewed-by: David Ahern <dsahern@gmail.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Alexander Yarygin <yarygin@linux.vnet.ibm.com>
Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>
Cc: Christian Borntraeger <borntraeger@de.ibm.com>
Cc: Cornelia Huck <cornelia.huck@de.ibm.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1404397747-20939-3-git-send-email-yarygin@linux.vnet.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/arch/x86/util/kvm-stat.c')
-rw-r--r-- | tools/perf/arch/x86/util/kvm-stat.c | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/tools/perf/arch/x86/util/kvm-stat.c b/tools/perf/arch/x86/util/kvm-stat.c new file mode 100644 index 000000000000..2f8d2c1af5ca --- /dev/null +++ b/tools/perf/arch/x86/util/kvm-stat.c | |||
@@ -0,0 +1,151 @@ | |||
1 | #include "../../util/kvm-stat.h" | ||
2 | #include <asm/kvm_perf.h> | ||
3 | |||
4 | define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS); | ||
5 | define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS); | ||
6 | |||
7 | static struct kvm_events_ops exit_events = { | ||
8 | .is_begin_event = exit_event_begin, | ||
9 | .is_end_event = exit_event_end, | ||
10 | .decode_key = exit_event_decode_key, | ||
11 | .name = "VM-EXIT" | ||
12 | }; | ||
13 | |||
14 | /* | ||
15 | * For the mmio events, we treat: | ||
16 | * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry | ||
17 | * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). | ||
18 | */ | ||
19 | static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample, | ||
20 | struct event_key *key) | ||
21 | { | ||
22 | key->key = perf_evsel__intval(evsel, sample, "gpa"); | ||
23 | key->info = perf_evsel__intval(evsel, sample, "type"); | ||
24 | } | ||
25 | |||
26 | #define KVM_TRACE_MMIO_READ_UNSATISFIED 0 | ||
27 | #define KVM_TRACE_MMIO_READ 1 | ||
28 | #define KVM_TRACE_MMIO_WRITE 2 | ||
29 | |||
30 | static bool mmio_event_begin(struct perf_evsel *evsel, | ||
31 | struct perf_sample *sample, struct event_key *key) | ||
32 | { | ||
33 | /* MMIO read begin event in kernel. */ | ||
34 | if (kvm_exit_event(evsel)) | ||
35 | return true; | ||
36 | |||
37 | /* MMIO write begin event in kernel. */ | ||
38 | if (!strcmp(evsel->name, "kvm:kvm_mmio") && | ||
39 | perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) { | ||
40 | mmio_event_get_key(evsel, sample, key); | ||
41 | return true; | ||
42 | } | ||
43 | |||
44 | return false; | ||
45 | } | ||
46 | |||
47 | static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample, | ||
48 | struct event_key *key) | ||
49 | { | ||
50 | /* MMIO write end event in kernel. */ | ||
51 | if (kvm_entry_event(evsel)) | ||
52 | return true; | ||
53 | |||
54 | /* MMIO read end event in kernel.*/ | ||
55 | if (!strcmp(evsel->name, "kvm:kvm_mmio") && | ||
56 | perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) { | ||
57 | mmio_event_get_key(evsel, sample, key); | ||
58 | return true; | ||
59 | } | ||
60 | |||
61 | return false; | ||
62 | } | ||
63 | |||
64 | static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, | ||
65 | struct event_key *key, | ||
66 | char *decode) | ||
67 | { | ||
68 | scnprintf(decode, DECODE_STR_LEN, "%#lx:%s", | ||
69 | (unsigned long)key->key, | ||
70 | key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); | ||
71 | } | ||
72 | |||
73 | static struct kvm_events_ops mmio_events = { | ||
74 | .is_begin_event = mmio_event_begin, | ||
75 | .is_end_event = mmio_event_end, | ||
76 | .decode_key = mmio_event_decode_key, | ||
77 | .name = "MMIO Access" | ||
78 | }; | ||
79 | |||
80 | /* The time of emulation pio access is from kvm_pio to kvm_entry. */ | ||
81 | static void ioport_event_get_key(struct perf_evsel *evsel, | ||
82 | struct perf_sample *sample, | ||
83 | struct event_key *key) | ||
84 | { | ||
85 | key->key = perf_evsel__intval(evsel, sample, "port"); | ||
86 | key->info = perf_evsel__intval(evsel, sample, "rw"); | ||
87 | } | ||
88 | |||
89 | static bool ioport_event_begin(struct perf_evsel *evsel, | ||
90 | struct perf_sample *sample, | ||
91 | struct event_key *key) | ||
92 | { | ||
93 | if (!strcmp(evsel->name, "kvm:kvm_pio")) { | ||
94 | ioport_event_get_key(evsel, sample, key); | ||
95 | return true; | ||
96 | } | ||
97 | |||
98 | return false; | ||
99 | } | ||
100 | |||
101 | static bool ioport_event_end(struct perf_evsel *evsel, | ||
102 | struct perf_sample *sample __maybe_unused, | ||
103 | struct event_key *key __maybe_unused) | ||
104 | { | ||
105 | return kvm_entry_event(evsel); | ||
106 | } | ||
107 | |||
108 | static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused, | ||
109 | struct event_key *key, | ||
110 | char *decode) | ||
111 | { | ||
112 | scnprintf(decode, DECODE_STR_LEN, "%#llx:%s", | ||
113 | (unsigned long long)key->key, | ||
114 | key->info ? "POUT" : "PIN"); | ||
115 | } | ||
116 | |||
117 | static struct kvm_events_ops ioport_events = { | ||
118 | .is_begin_event = ioport_event_begin, | ||
119 | .is_end_event = ioport_event_end, | ||
120 | .decode_key = ioport_event_decode_key, | ||
121 | .name = "IO Port Access" | ||
122 | }; | ||
123 | |||
124 | const char * const kvm_events_tp[] = { | ||
125 | "kvm:kvm_entry", | ||
126 | "kvm:kvm_exit", | ||
127 | "kvm:kvm_mmio", | ||
128 | "kvm:kvm_pio", | ||
129 | NULL, | ||
130 | }; | ||
131 | |||
132 | struct kvm_reg_events_ops kvm_reg_events_ops[] = { | ||
133 | { .name = "vmexit", .ops = &exit_events }, | ||
134 | { .name = "mmio", .ops = &mmio_events }, | ||
135 | { .name = "ioport", .ops = &ioport_events }, | ||
136 | { NULL, NULL }, | ||
137 | }; | ||
138 | |||
139 | int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid) | ||
140 | { | ||
141 | if (strstr(cpuid, "Intel")) { | ||
142 | kvm->exit_reasons = vmx_exit_reasons; | ||
143 | kvm->exit_reasons_isa = "VMX"; | ||
144 | } else if (strstr(cpuid, "AMD")) { | ||
145 | kvm->exit_reasons = svm_exit_reasons; | ||
146 | kvm->exit_reasons_isa = "SVM"; | ||
147 | } else | ||
148 | return -ENOTSUP; | ||
149 | |||
150 | return 0; | ||
151 | } | ||