2015-08-31 06:55:30

by Hemant Kumar

[permalink] [raw]
Subject: [PATCH v6 1/3] perf,kvm/powerpc: Remove const from kvm_events_tp

This patch removes the "const" qualifier from kvm_events_tp declaration
to account for the fact that powerpc will need to update this variable
dynamically depending on the machine type.

Signed-off-by: Hemant Kumar <[email protected]>
---
tools/perf/arch/s390/util/kvm-stat.c | 2 +-
tools/perf/arch/x86/util/kvm-stat.c | 2 +-
tools/perf/util/kvm-stat.h | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/tools/perf/arch/s390/util/kvm-stat.c b/tools/perf/arch/s390/util/kvm-stat.c
index a5dbc07..488a8c7 100644
--- a/tools/perf/arch/s390/util/kvm-stat.c
+++ b/tools/perf/arch/s390/util/kvm-stat.c
@@ -73,7 +73,7 @@ static struct kvm_events_ops exit_events = {
.name = "VM-EXIT"
};

-const char * const kvm_events_tp[] = {
+const char *kvm_events_tp[] = {
"kvm:kvm_s390_sie_enter",
"kvm:kvm_s390_sie_exit",
"kvm:kvm_s390_intercept_instruction",
diff --git a/tools/perf/arch/x86/util/kvm-stat.c b/tools/perf/arch/x86/util/kvm-stat.c
index 14e4e66..11188d5 100644
--- a/tools/perf/arch/x86/util/kvm-stat.c
+++ b/tools/perf/arch/x86/util/kvm-stat.c
@@ -121,7 +121,7 @@ static struct kvm_events_ops ioport_events = {
.name = "IO Port Access"
};

-const char * const kvm_events_tp[] = {
+const char *kvm_events_tp[] = {
"kvm:kvm_entry",
"kvm:kvm_exit",
"kvm:kvm_mmio",
diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h
index ae825d4..6384672 100644
--- a/tools/perf/util/kvm-stat.h
+++ b/tools/perf/util/kvm-stat.h
@@ -133,7 +133,7 @@ bool kvm_entry_event(struct perf_evsel *evsel);
*/
int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid);

-extern const char * const kvm_events_tp[];
+extern const char *kvm_events_tp[];
extern struct kvm_reg_events_ops kvm_reg_events_ops[];
extern const char * const kvm_skip_events[];

--
1.9.3


2015-08-31 06:55:35

by Hemant Kumar

[permalink] [raw]
Subject: [PATCH v6 2/3] perf,kvm/powerpc: Port perf kvm stat to powerpc

perf kvm can be used to analyze guest exit reasons. This support already
exists in x86. Hence, porting it to powerpc.

- To trace KVM events :
perf kvm stat record
If many guests are running, we can track for a specific guest by using
--pid as in : perf kvm stat record --pid <pid>

- To see the results :
perf kvm stat report

The result shows the number of exits (from the guest context to
host/hypervisor context) grouped by their respective exit reasons with
their frequency.

Since, different powerpc machines have different KVM tracepoints, this
patch discovers the machine type dynamically from /proc/cpuinfo's
"machine" tag and accordingly sets kvm tracepoints. Right now, it only
supports Book3S_HV tracepoints.

To analyze the different exits, group them and present them (in a slight
descriptive way) to the user, we need a mapping between the "exit
code" (dumped in the kvm_guest_exit tracepoint data) and to its related
Interrupt vector description (exit reason). This patch adds this mapping
in book3s_hv_exits.h.

It records on two available KVM tracepoints :
"kvm_hv:kvm_guest_exit" and "kvm_hv:kvm_guest_enter" exported through
arch/powerpc/include/uapi/asm/kvm_perf.h.

Here is a sample o/p:
# pgrep qemu
19378
60515

2 Guests are running on the host.

# perf kvm stat record -a
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 4.153 MB perf.data.guest (39624
samples) ]

# perf kvm stat report -p 60515

Analyze events for pid(s) 60515, all VCPUs:

VM-EXIT Samples Samples% Time% Min Time Max Time Avg time

SYSCALL 9141 63.67% 7.49% 1.26us 5782.39us 9.87us ( +- 6.46% )
H_DATA_STORAGE 4114 28.66% 5.07% 1.72us 4597.68us 14.84us ( +- 20.06% )
HV_DECREMENTER 418 2.91% 4.26% 0.70us 30002.22us 122.58us ( +- 70.29% )
EXTERNAL 392 2.73% 0.06% 0.64us 104.10us 1.94us ( +- 18.83% )
RETURN_TO_HOST 287 2.00% 83.11% 1.53us 124240.15us 3486.52us ( +- 16.81% )
H_INST_STORAGE 5 0.03% 0.00% 1.88us 3.73us 2.39us ( +- 14.20% )

Total Samples:14357, Total events handled time:1203918.42us.

Signed-off-by: Srikar Dronamraju <[email protected]>
Signed-off-by: Hemant Kumar <[email protected]>
---
This patch has a direct dependency on :
http://www.mail-archive.com/[email protected]/msg93620.html

Changes since v5 :
- Added a dynamic discovery check for machine type.
- Made the kvm tracepoints recording/reporting conditional on machine type.
(Suggested by Scott Wood)

tools/perf/arch/powerpc/Makefile | 2 +
tools/perf/arch/powerpc/util/Build | 1 +
tools/perf/arch/powerpc/util/book3s_hv_exits.h | 33 ++++++
tools/perf/arch/powerpc/util/kvm-stat.c | 151 +++++++++++++++++++++++++
tools/perf/builtin-kvm.c | 16 ++-
tools/perf/util/kvm-stat.h | 1 +
6 files changed, 201 insertions(+), 3 deletions(-)
create mode 100644 tools/perf/arch/powerpc/util/book3s_hv_exits.h
create mode 100644 tools/perf/arch/powerpc/util/kvm-stat.c

diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile
index 7fbca17..9f9cea3 100644
--- a/tools/perf/arch/powerpc/Makefile
+++ b/tools/perf/arch/powerpc/Makefile
@@ -1,3 +1,5 @@
ifndef NO_DWARF
PERF_HAVE_DWARF_REGS := 1
endif
+
+HAVE_KVM_STAT_SUPPORT := 1
diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
index 7b8b0d1..c8fe207 100644
--- a/tools/perf/arch/powerpc/util/Build
+++ b/tools/perf/arch/powerpc/util/Build
@@ -1,5 +1,6 @@
libperf-y += header.o
libperf-y += sym-handling.o
+libperf-y += kvm-stat.o

libperf-$(CONFIG_DWARF) += dwarf-regs.o
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 0000000..e68ba2d
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/book3s_hv_exits.h
@@ -0,0 +1,33 @@
+#ifndef ARCH_PERF_BOOK3S_HV_EXITS_H
+#define ARCH_PERF_BOOK3S_HV_EXITS_H
+
+/*
+ * PowerPC Interrupt vectors : exit code to name mapping
+ */
+
+#define kvm_trace_symbol_exit \
+ {0x0, "RETURN_TO_HOST"}, \
+ {0x100, "SYSTEM_RESET"}, \
+ {0x200, "MACHINE_CHECK"}, \
+ {0x300, "DATA_STORAGE"}, \
+ {0x380, "DATA_SEGMENT"}, \
+ {0x400, "INST_STORAGE"}, \
+ {0x480, "INST_SEGMENT"}, \
+ {0x500, "EXTERNAL"}, \
+ {0x501, "EXTERNAL_LEVEL"}, \
+ {0x502, "EXTERNAL_HV"}, \
+ {0x600, "ALIGNMENT"}, \
+ {0x700, "PROGRAM"}, \
+ {0x800, "FP_UNAVAIL"}, \
+ {0x900, "DECREMENTER"}, \
+ {0x980, "HV_DECREMENTER"}, \
+ {0xc00, "SYSCALL"}, \
+ {0xd00, "TRACE"}, \
+ {0xe00, "H_DATA_STORAGE"}, \
+ {0xe20, "H_INST_STORAGE"}, \
+ {0xe40, "H_EMUL_ASSIST"}, \
+ {0xf00, "PERFMON"}, \
+ {0xf20, "ALTIVEC"}, \
+ {0xf40, "VSX"}
+
+#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 0000000..448bc51
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/kvm-stat.c
@@ -0,0 +1,151 @@
+#include "../../util/kvm-stat.h"
+#include "book3s_hv_exits.h"
+#include <asm/kvm_perf.h>
+
+#define PPC_HV "PowerNV"
+#define KEY "machine"
+#define VM_ENTRY 0
+#define VM_EXIT 1
+#define NR_TPS 2
+
+/* Currently only supported on Book3S_HV machines */
+enum {
+ UNSUPPORTED = -1,
+ BOOK3S_HV = 0,
+} ppc_machine;
+
+define_exit_reasons_table(hv_exit_reasons, kvm_trace_symbol_exit);
+
+int ppc_type = UNSUPPORTED;
+const char *exit_reason;
+
+static struct kvm_events_ops exit_events = {
+ .is_begin_event = exit_event_begin,
+ .is_end_event = exit_event_end,
+ .decode_key = exit_event_decode_key,
+ .name = "VM-EXIT"
+};
+
+/* 1 extra placeholder for NULL */
+const char *kvm_events_tp[NR_TPS + 1];
+
+struct kvm_reg_events_ops kvm_reg_events_ops[] = {
+ { .name = "vmexit", .ops = &exit_events },
+ { NULL, NULL },
+};
+
+const char * const kvm_skip_events[] = {
+ NULL,
+};
+
+bool kvm_exit_event(struct perf_evsel *evsel)
+{
+ return !strncmp(evsel->name, kvm_events_tp[VM_EXIT],
+ strlen(kvm_events_tp[VM_EXIT]));
+}
+
+bool kvm_entry_event(struct perf_evsel *evsel)
+{
+ return !strncmp(evsel->name, kvm_events_tp[VM_ENTRY],
+ strlen(kvm_events_tp[VM_ENTRY]));
+}
+
+void exit_event_get_key(struct perf_evsel *evsel,
+ struct perf_sample *sample,
+ struct event_key *key)
+{
+ key->info = 0;
+ key->key = perf_evsel__intval(evsel, sample, exit_reason);
+}
+
+/*
+ * Read the /proc/cpuinfo and find out the machine type
+ */
+static int find_ppc_type(void)
+{
+ FILE *file;
+ char *s, *p, *buf = NULL;
+ size_t len;
+ int ret = UNSUPPORTED;
+
+ file = fopen("/proc/cpuinfo", "r");
+ if (!file)
+ return -1;
+
+ while (getline(&buf, &len, file) > 0) {
+ ret = strncmp(buf, KEY, strlen(KEY));
+ if (!ret)
+ break;
+ }
+
+ if (ret) {
+ ret = -1;
+ goto done;
+ }
+
+ s = buf;
+ p = strchr(buf, ':');
+ if (p && *(p + 1) == ' ' && *(p + 2))
+ s = p + 2;
+
+ p = strchr(s, '\n');
+ if (p)
+ *p = '\0';
+
+ /* s has the machine type now */
+ if (!strncmp(s, PPC_HV, strlen(PPC_HV))) {
+ ret = BOOK3S_HV;
+ ppc_type = ret;
+ }
+
+done:
+ free(buf);
+ fclose(file);
+ return ret;
+}
+
+/*
+ * Depending on the machine type, setup the KVM tracepoints
+ */
+static int setup_kvm_tp(void)
+{
+ int ret;
+
+ ret = find_ppc_type();
+ switch (ret) {
+ case BOOK3S_HV:
+ /* Tracepoints related to Book3S_HV machines */
+ kvm_events_tp[VM_ENTRY] = KVM_ENTRY_TRACE_HV;
+ kvm_events_tp[VM_EXIT] = KVM_EXIT_TRACE_HV;
+ kvm_events_tp[NR_TPS] = NULL;
+ exit_reason = KVM_EXIT_REASON_HV;
+ break;
+ default:
+ kvm_events_tp[0] = NULL;
+ ret = UNSUPPORTED;
+ exit_reason = NULL;
+ }
+ return ret;
+}
+
+int setup_kvm_events_tp(void)
+{
+ return setup_kvm_tp();
+}
+
+int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid __maybe_unused)
+{
+ int ret = 0;
+
+ ret = setup_kvm_tp();
+ if (ret == BOOK3S_HV) {
+ kvm->exit_reasons = hv_exit_reasons;
+ kvm->exit_reasons_isa = "HV";
+ ret = 0;
+ } else {
+ kvm->exit_reasons = NULL;
+ kvm->exit_reasons_isa = NULL;
+ }
+
+ return ret;
+}
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index fc1cffb..87db36a 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -34,7 +34,7 @@
#include <asm/kvm_perf.h>
#include "util/kvm-stat.h"

-void exit_event_get_key(struct perf_evsel *evsel,
+void __weak exit_event_get_key(struct perf_evsel *evsel,
struct perf_sample *sample,
struct event_key *key)
{
@@ -42,7 +42,7 @@ void exit_event_get_key(struct perf_evsel *evsel,
key->key = perf_evsel__intval(evsel, sample, KVM_EXIT_REASON);
}

-bool kvm_exit_event(struct perf_evsel *evsel)
+bool __weak kvm_exit_event(struct perf_evsel *evsel)
{
return !strcmp(evsel->name, KVM_EXIT_TRACE);
}
@@ -58,7 +58,7 @@ bool exit_event_begin(struct perf_evsel *evsel,
return false;
}

-bool kvm_entry_event(struct perf_evsel *evsel)
+bool __weak kvm_entry_event(struct perf_evsel *evsel)
{
return !strcmp(evsel->name, KVM_ENTRY_TRACE);
}
@@ -1125,6 +1125,11 @@ exit:
return ret;
}

+int __weak setup_kvm_events_tp(void)
+{
+ return 0;
+}
+
#define STRDUP_FAIL_EXIT(s) \
({ char *_p; \
_p = strdup(s); \
@@ -1149,7 +1154,12 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
NULL
};
const char * const *events_tp;
+ int ret;
+
events_tp_size = 0;
+ ret = setup_kvm_events_tp();
+ if (ret < 0)
+ return -EINVAL;

for (events_tp = kvm_events_tp; *events_tp; events_tp++)
events_tp_size++;
diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h
index 6384672..f8f778b 100644
--- a/tools/perf/util/kvm-stat.h
+++ b/tools/perf/util/kvm-stat.h
@@ -136,5 +136,6 @@ int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid);
extern const char *kvm_events_tp[];
extern struct kvm_reg_events_ops kvm_reg_events_ops[];
extern const char * const kvm_skip_events[];
+int setup_kvm_events_tp(void);

#endif /* __PERF_KVM_STAT_H */
--
1.9.3

2015-08-31 06:55:57

by Hemant Kumar

[permalink] [raw]
Subject: [PATCH v6 3/3] perf,kvm/powerpc: Add support for HCALL reasons

Powerpc provides hcall events that also provides insights into guest
behaviour. Enhance perf kvm to record and analyze hcall events.

- To trace hcall events :
perf kvm stat record

- To show the results :
perf kvm stat report --event=hcall

The result shows the number of hypervisor calls from the guest grouped
by their respective reasons displayed with the frequency.

This patch makes use of two additional tracepoints
"kvm_hv:kvm_hcall_enter" and "kvm_hv:kvm_hcall_exit". To map the hcall
codes to their respective names, it needs a mapping. Such mapping is
added in this patch in book3s_hcalls.h.

# pgrep qemu
A sample output :
19378
60515

2 VMs running.

# perf kvm stat record -a
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 4.153 MB perf.data.guest (39624
samples) ]

# perf kvm stat report -p 60515 --event=hcall

Analyze events for all VMs, all VCPUs:

HCALL-EVENT Samples Samples% Time% Min Time Max Time Avg time

H_IPI 822 66.08% 88.10% 0.63us 11.38us 2.05us ( +- 1.42% )
H_SEND_CRQ 144 11.58% 3.77% 0.41us 0.88us 0.50us ( +- 1.47% )
H_VIO_SIGNAL 118 9.49% 2.86% 0.37us 0.83us 0.47us ( +- 1.43% )
H_PUT_TERM_CHAR 76 6.11% 2.07% 0.37us 0.90us 0.52us ( +- 2.43% )
H_GET_TERM_CHAR 74 5.95% 2.23% 0.37us 1.70us 0.58us ( +- 4.77% )
H_RTAS 6 0.48% 0.85% 1.10us 9.25us 2.70us ( +- 48.57% )
H_PERFMON 4 0.32% 0.12% 0.41us 0.96us 0.59us ( +- 20.92% )

Total Samples:1244, Total events handled time:1916.69us.

Signed-off-by: Hemant Kumar <[email protected]>
---
This patch has a direct dependency on :
http://www.mail-archive.com/[email protected]/msg93619.html

Changes since v5:
- hcall tracepoints recording/reporting will be based on machine type check.

tools/perf/arch/powerpc/util/book3s_hcalls.h | 123 +++++++++++++++++++++++++++
tools/perf/arch/powerpc/util/kvm-stat.c | 76 +++++++++++++++--
2 files changed, 193 insertions(+), 6 deletions(-)
create mode 100644 tools/perf/arch/powerpc/util/book3s_hcalls.h

diff --git a/tools/perf/arch/powerpc/util/book3s_hcalls.h b/tools/perf/arch/powerpc/util/book3s_hcalls.h
new file mode 100644
index 0000000..0dd6b7f
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/book3s_hcalls.h
@@ -0,0 +1,123 @@
+#ifndef ARCH_PERF_BOOK3S_HV_HCALLS_H
+#define ARCH_PERF_BOOK3S_HV_HCALLS_H
+
+/*
+ * PowerPC HCALL codes : hcall code to name mapping
+ */
+#define kvm_trace_symbol_hcall \
+ {0x4, "H_REMOVE"}, \
+ {0x8, "H_ENTER"}, \
+ {0xc, "H_READ"}, \
+ {0x10, "H_CLEAR_MOD"}, \
+ {0x14, "H_CLEAR_REF"}, \
+ {0x18, "H_PROTECT"}, \
+ {0x1c, "H_GET_TCE"}, \
+ {0x20, "H_PUT_TCE"}, \
+ {0x24, "H_SET_SPRG0"}, \
+ {0x28, "H_SET_DABR"}, \
+ {0x2c, "H_PAGE_INIT"}, \
+ {0x30, "H_SET_ASR"}, \
+ {0x34, "H_ASR_ON"}, \
+ {0x38, "H_ASR_OFF"}, \
+ {0x3c, "H_LOGICAL_CI_LOAD"}, \
+ {0x40, "H_LOGICAL_CI_STORE"}, \
+ {0x44, "H_LOGICAL_CACHE_LOAD"}, \
+ {0x48, "H_LOGICAL_CACHE_STORE"}, \
+ {0x4c, "H_LOGICAL_ICBI"}, \
+ {0x50, "H_LOGICAL_DCBF"}, \
+ {0x54, "H_GET_TERM_CHAR"}, \
+ {0x58, "H_PUT_TERM_CHAR"}, \
+ {0x5c, "H_REAL_TO_LOGICAL"}, \
+ {0x60, "H_HYPERVISOR_DATA"}, \
+ {0x64, "H_EOI"}, \
+ {0x68, "H_CPPR"}, \
+ {0x6c, "H_IPI"}, \
+ {0x70, "H_IPOLL"}, \
+ {0x74, "H_XIRR"}, \
+ {0x78, "H_MIGRATE_DMA"}, \
+ {0x7c, "H_PERFMON"}, \
+ {0xdc, "H_REGISTER_VPA"}, \
+ {0xe0, "H_CEDE"}, \
+ {0xe4, "H_CONFER"}, \
+ {0xe8, "H_PROD"}, \
+ {0xec, "H_GET_PPP"}, \
+ {0xf0, "H_SET_PPP"}, \
+ {0xf4, "H_PURR"}, \
+ {0xf8, "H_PIC"}, \
+ {0xfc, "H_REG_CRQ"}, \
+ {0x100, "H_FREE_CRQ"}, \
+ {0x104, "H_VIO_SIGNAL"}, \
+ {0x108, "H_SEND_CRQ"}, \
+ {0x110, "H_COPY_RDMA"}, \
+ {0x114, "H_REGISTER_LOGICAL_LAN"}, \
+ {0x118, "H_FREE_LOGICAL_LAN"}, \
+ {0x11c, "H_ADD_LOGICAL_LAN_BUFFER"}, \
+ {0x120, "H_SEND_LOGICAL_LAN"}, \
+ {0x124, "H_BULK_REMOVE"}, \
+ {0x130, "H_MULTICAST_CTRL"}, \
+ {0x134, "H_SET_XDABR"}, \
+ {0x138, "H_STUFF_TCE"}, \
+ {0x13c, "H_PUT_TCE_INDIRECT"}, \
+ {0x14c, "H_CHANGE_LOGICAL_LAN_MAC"}, \
+ {0x150, "H_VTERM_PARTNER_INFO"}, \
+ {0x154, "H_REGISTER_VTERM"}, \
+ {0x158, "H_FREE_VTERM"}, \
+ {0x15c, "H_RESET_EVENTS"}, \
+ {0x160, "H_ALLOC_RESOURCE"}, \
+ {0x164, "H_FREE_RESOURCE"}, \
+ {0x168, "H_MODIFY_QP"}, \
+ {0x16c, "H_QUERY_QP"}, \
+ {0x170, "H_REREGISTER_PMR"}, \
+ {0x174, "H_REGISTER_SMR"}, \
+ {0x178, "H_QUERY_MR"}, \
+ {0x17c, "H_QUERY_MW"}, \
+ {0x180, "H_QUERY_HCA"}, \
+ {0x184, "H_QUERY_PORT"}, \
+ {0x188, "H_MODIFY_PORT"}, \
+ {0x18c, "H_DEFINE_AQP1"}, \
+ {0x190, "H_GET_TRACE_BUFFER"}, \
+ {0x194, "H_DEFINE_AQP0"}, \
+ {0x198, "H_RESIZE_MR"}, \
+ {0x19c, "H_ATTACH_MCQP"}, \
+ {0x1a0, "H_DETACH_MCQP"}, \
+ {0x1a4, "H_CREATE_RPT"}, \
+ {0x1a8, "H_REMOVE_RPT"}, \
+ {0x1ac, "H_REGISTER_RPAGES"}, \
+ {0x1b0, "H_DISABLE_AND_GETC"}, \
+ {0x1b4, "H_ERROR_DATA"}, \
+ {0x1b8, "H_GET_HCA_INFO"}, \
+ {0x1bc, "H_GET_PERF_COUNT"}, \
+ {0x1c0, "H_MANAGE_TRACE"}, \
+ {0x1d4, "H_FREE_LOGICAL_LAN_BUFFER"}, \
+ {0x1d8, "H_POLL_PENDING"}, \
+ {0x1e4, "H_QUERY_INT_STATE"}, \
+ {0x244, "H_ILLAN_ATTRIBUTES"}, \
+ {0x250, "H_MODIFY_HEA_QP"}, \
+ {0x254, "H_QUERY_HEA_QP"}, \
+ {0x258, "H_QUERY_HEA"}, \
+ {0x25c, "H_QUERY_HEA_PORT"}, \
+ {0x260, "H_MODIFY_HEA_PORT"}, \
+ {0x264, "H_REG_BCMC"}, \
+ {0x268, "H_DEREG_BCMC"}, \
+ {0x26c, "H_REGISTER_HEA_RPAGES"}, \
+ {0x270, "H_DISABLE_AND_GET_HEA"}, \
+ {0x274, "H_GET_HEA_INFO"}, \
+ {0x278, "H_ALLOC_HEA_RESOURCE"}, \
+ {0x284, "H_ADD_CONN"}, \
+ {0x288, "H_DEL_CONN"}, \
+ {0x298, "H_JOIN"}, \
+ {0x2a4, "H_VASI_STATE"}, \
+ {0x2b0, "H_ENABLE_CRQ"}, \
+ {0x2b8, "H_GET_EM_PARMS"}, \
+ {0x2d0, "H_SET_MPP"}, \
+ {0x2d4, "H_GET_MPP"}, \
+ {0x2ec, "H_HOME_NODE_ASSOCIATIVITY"}, \
+ {0x2f4, "H_BEST_ENERGY"}, \
+ {0x2fc, "H_XIRR_X"}, \
+ {0x300, "H_RANDOM"}, \
+ {0x304, "H_COP"}, \
+ {0x314, "H_GET_MPP_X"}, \
+ {0x31c, "H_SET_MODE"}, \
+ {0xf000, "H_RTAS"} \
+
+#endif
diff --git a/tools/perf/arch/powerpc/util/kvm-stat.c b/tools/perf/arch/powerpc/util/kvm-stat.c
index 448bc51..b78ad73 100644
--- a/tools/perf/arch/powerpc/util/kvm-stat.c
+++ b/tools/perf/arch/powerpc/util/kvm-stat.c
@@ -1,12 +1,16 @@
#include "../../util/kvm-stat.h"
+#include "../../util/debug.h"
#include "book3s_hv_exits.h"
+#include "book3s_hcalls.h"
#include <asm/kvm_perf.h>

#define PPC_HV "PowerNV"
#define KEY "machine"
#define VM_ENTRY 0
#define VM_EXIT 1
-#define NR_TPS 2
+#define HCALL_ENTRY 2
+#define HCALL_EXIT 3
+#define NR_TPS 4

/* Currently only supported on Book3S_HV machines */
enum {
@@ -15,6 +19,7 @@ enum {
} ppc_machine;

define_exit_reasons_table(hv_exit_reasons, kvm_trace_symbol_exit);
+define_exit_reasons_table(hcall_reasons, kvm_trace_symbol_hcall);

int ppc_type = UNSUPPORTED;
const char *exit_reason;
@@ -29,11 +34,6 @@ static struct kvm_events_ops exit_events = {
/* 1 extra placeholder for NULL */
const char *kvm_events_tp[NR_TPS + 1];

-struct kvm_reg_events_ops kvm_reg_events_ops[] = {
- { .name = "vmexit", .ops = &exit_events },
- { NULL, NULL },
-};
-
const char * const kvm_skip_events[] = {
NULL,
};
@@ -58,6 +58,68 @@ void exit_event_get_key(struct perf_evsel *evsel,
key->key = perf_evsel__intval(evsel, sample, exit_reason);
}

+static void hcall_event_get_key(struct perf_evsel *evsel,
+ struct perf_sample *sample,
+ struct event_key *key)
+{
+ key->info = 0;
+ key->key = perf_evsel__intval(evsel, sample, KVM_HCALL_REASON_HV);
+}
+
+static const char *get_exit_reason(u64 exit_code)
+{
+ struct exit_reasons_table *tbl = hcall_reasons;
+
+ while (tbl->reason != NULL) {
+ if (tbl->exit_code == exit_code)
+ return tbl->reason;
+ tbl++;
+ }
+
+ pr_err("Unknown kvm hcall exit code: %lld\n",
+ (unsigned long long)exit_code);
+ return "UNKNOWN";
+}
+
+static bool hcall_event_end(struct perf_evsel *evsel,
+ struct perf_sample *sample __maybe_unused,
+ struct event_key *key __maybe_unused)
+{
+ return (!strcmp(evsel->name, kvm_events_tp[HCALL_EXIT]));
+}
+
+static bool hcall_event_begin(struct perf_evsel *evsel,
+ struct perf_sample *sample, struct event_key *key)
+{
+ if (!strcmp(evsel->name, kvm_events_tp[HCALL_ENTRY])) {
+ hcall_event_get_key(evsel, sample, key);
+ return true;
+ }
+
+ return false;
+}
+static void hcall_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
+ struct event_key *key,
+ char *decode)
+{
+ const char *hcall_reason = get_exit_reason(key->key);
+
+ scnprintf(decode, DECODE_STR_LEN, "%s", hcall_reason);
+}
+
+static struct kvm_events_ops hcall_events = {
+ .is_begin_event = hcall_event_begin,
+ .is_end_event = hcall_event_end,
+ .decode_key = hcall_event_decode_key,
+ .name = "HCALL-EVENT",
+};
+
+struct kvm_reg_events_ops kvm_reg_events_ops[] = {
+ { .name = "vmexit", .ops = &exit_events },
+ { .name = "hcall", .ops = &hcall_events },
+ { NULL, NULL },
+};
+
/*
* Read the /proc/cpuinfo and find out the machine type
*/
@@ -117,6 +179,8 @@ static int setup_kvm_tp(void)
/* Tracepoints related to Book3S_HV machines */
kvm_events_tp[VM_ENTRY] = KVM_ENTRY_TRACE_HV;
kvm_events_tp[VM_EXIT] = KVM_EXIT_TRACE_HV;
+ kvm_events_tp[HCALL_ENTRY] = KVM_HCALL_ENTRY_TRACE_HV;
+ kvm_events_tp[HCALL_EXIT] = KVM_HCALL_EXIT_TRACE_HV;
kvm_events_tp[NR_TPS] = NULL;
exit_reason = KVM_EXIT_REASON_HV;
break;
--
1.9.3