aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/arch/powerpc/Makefile2
-rw-r--r--tools/perf/arch/powerpc/util/Build1
-rw-r--r--tools/perf/arch/powerpc/util/book3s_hv_exits.h33
-rw-r--r--tools/perf/arch/powerpc/util/kvm-stat.c107
-rw-r--r--tools/perf/builtin-kvm.c18
-rw-r--r--tools/perf/util/kvm-stat.h1
6 files changed, 162 insertions, 0 deletions
diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile
index 7fbca175099e..9f9cea3478fd 100644
--- a/tools/perf/arch/powerpc/Makefile
+++ b/tools/perf/arch/powerpc/Makefile
@@ -1,3 +1,5 @@
1ifndef NO_DWARF 1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3endif 3endif
4
5HAVE_KVM_STAT_SUPPORT := 1
diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
index 7b8b0d1a1b62..c8fe2074d217 100644
--- a/tools/perf/arch/powerpc/util/Build
+++ b/tools/perf/arch/powerpc/util/Build
@@ -1,5 +1,6 @@
1libperf-y += header.o 1libperf-y += header.o
2libperf-y += sym-handling.o 2libperf-y += sym-handling.o
3libperf-y += kvm-stat.o
3 4
4libperf-$(CONFIG_DWARF) += dwarf-regs.o 5libperf-$(CONFIG_DWARF) += dwarf-regs.o
5libperf-$(CONFIG_DWARF) += skip-callchain-idx.o 6libperf-$(CONFIG_DWARF) += skip-callchain-idx.o
diff --git a/tools/perf/arch/powerpc/util/book3s_hv_exits.h b/tools/perf/arch/powerpc/util/book3s_hv_exits.h
new file mode 100644
index 000000000000..e68ba2da8970
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/book3s_hv_exits.h
@@ -0,0 +1,33 @@
1#ifndef ARCH_PERF_BOOK3S_HV_EXITS_H
2#define ARCH_PERF_BOOK3S_HV_EXITS_H
3
4/*
5 * PowerPC Interrupt vectors : exit code to name mapping
6 */
7
8#define kvm_trace_symbol_exit \
9 {0x0, "RETURN_TO_HOST"}, \
10 {0x100, "SYSTEM_RESET"}, \
11 {0x200, "MACHINE_CHECK"}, \
12 {0x300, "DATA_STORAGE"}, \
13 {0x380, "DATA_SEGMENT"}, \
14 {0x400, "INST_STORAGE"}, \
15 {0x480, "INST_SEGMENT"}, \
16 {0x500, "EXTERNAL"}, \
17 {0x501, "EXTERNAL_LEVEL"}, \
18 {0x502, "EXTERNAL_HV"}, \
19 {0x600, "ALIGNMENT"}, \
20 {0x700, "PROGRAM"}, \
21 {0x800, "FP_UNAVAIL"}, \
22 {0x900, "DECREMENTER"}, \
23 {0x980, "HV_DECREMENTER"}, \
24 {0xc00, "SYSCALL"}, \
25 {0xd00, "TRACE"}, \
26 {0xe00, "H_DATA_STORAGE"}, \
27 {0xe20, "H_INST_STORAGE"}, \
28 {0xe40, "H_EMUL_ASSIST"}, \
29 {0xf00, "PERFMON"}, \
30 {0xf20, "ALTIVEC"}, \
31 {0xf40, "VSX"}
32
33#endif
diff --git a/tools/perf/arch/powerpc/util/kvm-stat.c b/tools/perf/arch/powerpc/util/kvm-stat.c
new file mode 100644
index 000000000000..27bc559b8b3a
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/kvm-stat.c
@@ -0,0 +1,107 @@
1#include "util/kvm-stat.h"
2#include "util/parse-events.h"
3
4#include "book3s_hv_exits.h"
5
6#define NR_TPS 2
7
8const char *vcpu_id_str = "vcpu_id";
9const int decode_str_len = 40;
10const char *kvm_entry_trace = "kvm_hv:kvm_guest_enter";
11const char *kvm_exit_trace = "kvm_hv:kvm_guest_exit";
12
13define_exit_reasons_table(hv_exit_reasons, kvm_trace_symbol_exit);
14
15/* Tracepoints specific to ppc_book3s_hv */
16const char *ppc_book3s_hv_kvm_tp[] = {
17 "kvm_hv:kvm_guest_enter",
18 "kvm_hv:kvm_guest_exit",
19};
20
21/* 1 extra placeholder for NULL */
22const char *kvm_events_tp[NR_TPS + 1];
23const char *kvm_exit_reason;
24
25static struct kvm_events_ops exit_events = {
26 .is_begin_event = exit_event_begin,
27 .is_end_event = exit_event_end,
28 .decode_key = exit_event_decode_key,
29 .name = "VM-EXIT"
30};
31
32struct kvm_reg_events_ops kvm_reg_events_ops[] = {
33 { .name = "vmexit", .ops = &exit_events },
34 { NULL, NULL },
35};
36
37const char * const kvm_skip_events[] = {
38 NULL,
39};
40
41
42static int is_tracepoint_available(const char *str, struct perf_evlist *evlist)
43{
44 struct parse_events_error err;
45 int ret;
46
47 err.str = NULL;
48 ret = parse_events(evlist, str, &err);
49 if (err.str)
50 pr_err("%s : %s\n", str, err.str);
51 return ret;
52}
53
54static int ppc__setup_book3s_hv(struct perf_kvm_stat *kvm,
55 struct perf_evlist *evlist)
56{
57 const char **events_ptr;
58 int i, nr_tp = 0, err = -1;
59
60 /* Check for book3s_hv tracepoints */
61 for (events_ptr = ppc_book3s_hv_kvm_tp; *events_ptr; events_ptr++) {
62 err = is_tracepoint_available(*events_ptr, evlist);
63 if (err)
64 return -1;
65 nr_tp++;
66 }
67
68 for (i = 0; i < nr_tp; i++)
69 kvm_events_tp[i] = ppc_book3s_hv_kvm_tp[i];
70
71 kvm_events_tp[i] = NULL;
72 kvm_exit_reason = "trap";
73 kvm->exit_reasons = hv_exit_reasons;
74 kvm->exit_reasons_isa = "HV";
75
76 return 0;
77}
78
79/* Wrapper to setup kvm tracepoints */
80static int ppc__setup_kvm_tp(struct perf_kvm_stat *kvm)
81{
82 struct perf_evlist *evlist = perf_evlist__new();
83
84 if (evlist == NULL)
85 return -ENOMEM;
86
87 /* Right now, only supported on book3s_hv */
88 return ppc__setup_book3s_hv(kvm, evlist);
89}
90
91int setup_kvm_events_tp(struct perf_kvm_stat *kvm)
92{
93 return ppc__setup_kvm_tp(kvm);
94}
95
96int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid __maybe_unused)
97{
98 int ret;
99
100 ret = ppc__setup_kvm_tp(kvm);
101 if (ret) {
102 kvm->exit_reasons = NULL;
103 kvm->exit_reasons_isa = NULL;
104 }
105
106 return ret;
107}
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index ab5645cf39d2..bff666458b28 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -1132,6 +1132,11 @@ exit:
1132 _p; \ 1132 _p; \
1133 }) 1133 })
1134 1134
1135int __weak setup_kvm_events_tp(struct perf_kvm_stat *kvm __maybe_unused)
1136{
1137 return 0;
1138}
1139
1135static int 1140static int
1136kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) 1141kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
1137{ 1142{
@@ -1148,7 +1153,14 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
1148 NULL 1153 NULL
1149 }; 1154 };
1150 const char * const *events_tp; 1155 const char * const *events_tp;
1156 int ret;
1157
1151 events_tp_size = 0; 1158 events_tp_size = 0;
1159 ret = setup_kvm_events_tp(kvm);
1160 if (ret < 0) {
1161 pr_err("Unable to setup the kvm tracepoints\n");
1162 return ret;
1163 }
1152 1164
1153 for (events_tp = kvm_events_tp; *events_tp; events_tp++) 1165 for (events_tp = kvm_events_tp; *events_tp; events_tp++)
1154 events_tp_size++; 1166 events_tp_size++;
@@ -1377,6 +1389,12 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1377 /* 1389 /*
1378 * generate the event list 1390 * generate the event list
1379 */ 1391 */
1392 err = setup_kvm_events_tp(kvm);
1393 if (err < 0) {
1394 pr_err("Unable to setup the kvm tracepoints\n");
1395 return err;
1396 }
1397
1380 kvm->evlist = kvm_live_event_list(); 1398 kvm->evlist = kvm_live_event_list();
1381 if (kvm->evlist == NULL) { 1399 if (kvm->evlist == NULL) {
1382 err = -1; 1400 err = -1;
diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h
index c965dc844df3..d01e73592f6e 100644
--- a/tools/perf/util/kvm-stat.h
+++ b/tools/perf/util/kvm-stat.h
@@ -122,6 +122,7 @@ void exit_event_decode_key(struct perf_kvm_stat *kvm,
122 122
123bool kvm_exit_event(struct perf_evsel *evsel); 123bool kvm_exit_event(struct perf_evsel *evsel);
124bool kvm_entry_event(struct perf_evsel *evsel); 124bool kvm_entry_event(struct perf_evsel *evsel);
125int setup_kvm_events_tp(struct perf_kvm_stat *kvm);
125 126
126#define define_exit_reasons_table(name, symbols) \ 127#define define_exit_reasons_table(name, symbols) \
127 static struct exit_reasons_table name[] = { \ 128 static struct exit_reasons_table name[] = { \