diff options
Diffstat (limited to 'tools/perf')
| -rw-r--r-- | tools/perf/arch/powerpc/Makefile | 2 | ||||
| -rw-r--r-- | tools/perf/arch/powerpc/util/Build | 1 | ||||
| -rw-r--r-- | tools/perf/arch/powerpc/util/book3s_hv_exits.h | 33 | ||||
| -rw-r--r-- | tools/perf/arch/powerpc/util/kvm-stat.c | 107 | ||||
| -rw-r--r-- | tools/perf/builtin-kvm.c | 18 | ||||
| -rw-r--r-- | tools/perf/util/kvm-stat.h | 1 |
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 @@ | |||
| 1 | ifndef NO_DWARF | 1 | ifndef NO_DWARF |
| 2 | PERF_HAVE_DWARF_REGS := 1 | 2 | PERF_HAVE_DWARF_REGS := 1 |
| 3 | endif | 3 | endif |
| 4 | |||
| 5 | HAVE_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 @@ | |||
| 1 | libperf-y += header.o | 1 | libperf-y += header.o |
| 2 | libperf-y += sym-handling.o | 2 | libperf-y += sym-handling.o |
| 3 | libperf-y += kvm-stat.o | ||
| 3 | 4 | ||
| 4 | libperf-$(CONFIG_DWARF) += dwarf-regs.o | 5 | libperf-$(CONFIG_DWARF) += dwarf-regs.o |
| 5 | libperf-$(CONFIG_DWARF) += skip-callchain-idx.o | 6 | libperf-$(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 | |||
| 8 | const char *vcpu_id_str = "vcpu_id"; | ||
| 9 | const int decode_str_len = 40; | ||
| 10 | const char *kvm_entry_trace = "kvm_hv:kvm_guest_enter"; | ||
| 11 | const char *kvm_exit_trace = "kvm_hv:kvm_guest_exit"; | ||
| 12 | |||
| 13 | define_exit_reasons_table(hv_exit_reasons, kvm_trace_symbol_exit); | ||
| 14 | |||
| 15 | /* Tracepoints specific to ppc_book3s_hv */ | ||
| 16 | const 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 */ | ||
| 22 | const char *kvm_events_tp[NR_TPS + 1]; | ||
| 23 | const char *kvm_exit_reason; | ||
| 24 | |||
| 25 | static 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 | |||
| 32 | struct kvm_reg_events_ops kvm_reg_events_ops[] = { | ||
| 33 | { .name = "vmexit", .ops = &exit_events }, | ||
| 34 | { NULL, NULL }, | ||
| 35 | }; | ||
| 36 | |||
| 37 | const char * const kvm_skip_events[] = { | ||
| 38 | NULL, | ||
| 39 | }; | ||
| 40 | |||
| 41 | |||
| 42 | static 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 | |||
| 54 | static 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 */ | ||
| 80 | static 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 | |||
| 91 | int setup_kvm_events_tp(struct perf_kvm_stat *kvm) | ||
| 92 | { | ||
| 93 | return ppc__setup_kvm_tp(kvm); | ||
| 94 | } | ||
| 95 | |||
| 96 | int 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 | ||
| 1135 | int __weak setup_kvm_events_tp(struct perf_kvm_stat *kvm __maybe_unused) | ||
| 1136 | { | ||
| 1137 | return 0; | ||
| 1138 | } | ||
| 1139 | |||
| 1135 | static int | 1140 | static int |
| 1136 | kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) | 1141 | kvm_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 | ||
| 123 | bool kvm_exit_event(struct perf_evsel *evsel); | 123 | bool kvm_exit_event(struct perf_evsel *evsel); |
| 124 | bool kvm_entry_event(struct perf_evsel *evsel); | 124 | bool kvm_entry_event(struct perf_evsel *evsel); |
| 125 | int 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[] = { \ |
