[RFC 1/4] perf kvm: Enable 'record' on powerpc

From: Ravi Bangoria
Date: Wed Feb 24 2016 - 04:09:12 EST


'perf kvm record' is not available on powerpc because 'perf' relies on
the 'cycles' event (a PMU event) to profile the guest. However, for
powerpc, this can't be used from the host because the PMUs are controlled
by the guest rather than the host.

There exists a tracepoint 'kvm_hv:kvm_guest_exit' in powerpc which is
hit whenever any of the threads exit the guest context. The guest
instruction pointer dumped along with this tracepoint data in the field
'pc', can be used as guest instruction pointer.

This patch changes default event as kvm_hv:kvm_guest_exit for recording
guest data in host on powerpc. As we are using host event to record guest
data, this approach will enable only --guest option of 'perf kvm'. Still
--host --guest together won't work.

Signed-off-by: Ravi Bangoria <ravi.bangoria@xxxxxxxxxxxxxxxxxx>
---
tools/perf/arch/powerpc/util/Build | 1 +
tools/perf/arch/powerpc/util/kvm.c | 18 ++++++++++++++++++
tools/perf/util/evlist.c | 9 +++++++++
tools/perf/util/evlist.h | 1 +
tools/perf/util/util.c | 5 +++++
tools/perf/util/util.h | 1 +
6 files changed, 35 insertions(+)
create mode 100644 tools/perf/arch/powerpc/util/kvm.c

diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
index c8fe207..4cb620d 100644
--- a/tools/perf/arch/powerpc/util/Build
+++ b/tools/perf/arch/powerpc/util/Build
@@ -1,6 +1,7 @@
libperf-y += header.o
libperf-y += sym-handling.o
libperf-y += kvm-stat.o
+libperf-y += kvm.o

libperf-$(CONFIG_DWARF) += dwarf-regs.o
libperf-$(CONFIG_DWARF) += skip-callchain-idx.o
diff --git a/tools/perf/arch/powerpc/util/kvm.c b/tools/perf/arch/powerpc/util/kvm.c
new file mode 100644
index 0000000..878d323
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/kvm.c
@@ -0,0 +1,18 @@
+#include <linux/err.h>
+#include "../../../util/evsel.h"
+#include "../../../util/evlist.h"
+
+int perf_evlist__arch_add_default(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel;
+
+ if (!perf_guest_only())
+ return -1;
+
+ evsel = perf_evsel__newtp_idx("kvm_hv", "kvm_guest_exit", 0);
+ if (IS_ERR(evsel))
+ return PTR_ERR(evsel);
+
+ perf_evlist__add(evlist, evsel);
+ return 0;
+}
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index c42e196..8b7b84f 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -231,6 +231,12 @@ void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr)
}
}

+int __weak
+perf_evlist__arch_add_default(struct perf_evlist *evlist __maybe_unused)
+{
+ return -1;
+}
+
int perf_evlist__add_default(struct perf_evlist *evlist)
{
struct perf_event_attr attr = {
@@ -239,6 +245,9 @@ int perf_evlist__add_default(struct perf_evlist *evlist)
};
struct perf_evsel *evsel;

+ if (!perf_evlist__arch_add_default(evlist))
+ return 0;
+
event_attr_init(&attr);

perf_event_attr__set_max_precise_ip(&attr);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index a0d1522..7951406 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -75,6 +75,7 @@ void perf_evlist__delete(struct perf_evlist *evlist);

void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry);
void perf_evlist__remove(struct perf_evlist *evlist, struct perf_evsel *evsel);
+int perf_evlist__arch_add_default(struct perf_evlist *evlist);
int perf_evlist__add_default(struct perf_evlist *evlist);
int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
struct perf_event_attr *attrs, size_t nr_attrs);
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 35b20dd..567e3da 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -37,6 +37,11 @@ bool test_attr__enabled;
bool perf_host = true;
bool perf_guest = false;

+bool perf_guest_only(void)
+{
+ return !perf_host && perf_guest;
+}
+
void event_attr_init(struct perf_event_attr *attr)
{
if (!perf_host)
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 3dd0408..c459c45 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -344,5 +344,6 @@ int fetch_kernel_version(unsigned int *puint,
const char *perf_tip(const char *dirpath);
bool is_regular_file(const char *file);
int fetch_current_timestamp(char *buf, size_t sz);
+bool perf_guest_only(void);

#endif /* GIT_COMPAT_UTIL_H */
--
2.1.4